This is an automated email from the ASF dual-hosted git repository.
xiong pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 1d4b1fd6e9 [CALCITE-7030] Enhance TopologicalOrderIterator to support
BOTTOM_UP
1d4b1fd6e9 is described below
commit 1d4b1fd6e9e6953f43ee5c985b3e4aa10ce568e1
Author: Xiong Duan <[email protected]>
AuthorDate: Tue May 20 19:30:09 2025 +0800
[CALCITE-7030] Enhance TopologicalOrderIterator to support BOTTOM_UP
---
.../org/apache/calcite/plan/hep/HepPlanner.java | 23 ++-----
.../calcite/util/graph/DefaultDirectedGraph.java | 1 +
.../util/graph/TopologicalOrderIterator.java | 77 +++++++++++++++++-----
.../calcite/util/graph/DirectedGraphTest.java | 15 +++++
4 files changed, 80 insertions(+), 36 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java
b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java
index fd5687e40c..1349930ae8 100644
--- a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java
@@ -58,7 +58,6 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -467,30 +466,16 @@ private Iterator<HepRelVertex> getGraphIterator(
return DepthFirstIterator.of(graph, start).iterator();
case TOP_DOWN:
- assert start == root;
- // see above
-/*
- collectGarbage();
-*/
- return TopologicalOrderIterator.of(graph).iterator();
-
case BOTTOM_UP:
- default:
assert start == root;
-
// see above
/*
collectGarbage();
*/
-
- // TODO jvs 4-Apr-2006: enhance TopologicalOrderIterator
- // to support reverse walk.
- final List<HepRelVertex> list = new ArrayList<>();
- for (HepRelVertex vertex : TopologicalOrderIterator.of(graph)) {
- list.add(vertex);
- }
- Collections.reverse(list);
- return list.iterator();
+ return TopologicalOrderIterator.of(graph,
programState.matchOrder).iterator();
+ default:
+ throw new
+ UnsupportedOperationException("Unsupported match order: " +
programState.matchOrder);
}
}
diff --git
a/core/src/main/java/org/apache/calcite/util/graph/DefaultDirectedGraph.java
b/core/src/main/java/org/apache/calcite/util/graph/DefaultDirectedGraph.java
index b1590f9ed3..71c14ca89e 100644
--- a/core/src/main/java/org/apache/calcite/util/graph/DefaultDirectedGraph.java
+++ b/core/src/main/java/org/apache/calcite/util/graph/DefaultDirectedGraph.java
@@ -61,6 +61,7 @@ public static <V, E extends DefaultEdge>
DefaultDirectedGraph<V, E> create(
return new DefaultDirectedGraph<>(edgeFactory);
}
+ @Deprecated
public String toStringUnordered() {
return "graph("
+ "vertices: " + vertexMap.keySet()
diff --git
a/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java
b/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java
index 024eba3947..e880d72e4f 100644
---
a/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java
+++
b/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java
@@ -16,6 +16,8 @@
*/
package org.apache.calcite.util.graph;
+import org.apache.calcite.plan.hep.HepMatchOrder;
+
import org.checkerframework.checker.initialization.qual.UnderInitialization;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@@ -38,10 +40,17 @@ public class TopologicalOrderIterator<V, E extends
DefaultEdge>
implements Iterator<V> {
final Map<V, int[]> countMap = new HashMap<>();
final List<V> empties = new ArrayList<>();
+ final HepMatchOrder hepMatchOrder;
private final DefaultDirectedGraph<V, E> graph;
public TopologicalOrderIterator(DirectedGraph<V, E> graph) {
+ this(graph, HepMatchOrder.TOP_DOWN);
+ }
+
+ public TopologicalOrderIterator(DirectedGraph<V, E> graph, HepMatchOrder
hepMatchOrder) {
+ assert hepMatchOrder == HepMatchOrder.TOP_DOWN || hepMatchOrder ==
HepMatchOrder.BOTTOM_UP;
this.graph = (DefaultDirectedGraph<V, E>) graph;
+ this.hepMatchOrder = hepMatchOrder;
populate(countMap, empties);
}
@@ -50,6 +59,11 @@ public static <V, E extends DefaultEdge> Iterable<V> of(
return () -> new TopologicalOrderIterator<>(graph);
}
+ public static <V, E extends DefaultEdge> Iterable<V> of(
+ final DirectedGraph<V, E> graph, HepMatchOrder hepMatchOrder) {
+ return () -> new TopologicalOrderIterator<>(graph, hepMatchOrder);
+ }
+
@RequiresNonNull("graph")
private void populate(
@UnderInitialization TopologicalOrderIterator<V, E> this,
@@ -57,14 +71,28 @@ private void populate(
for (V v : graph.vertexMap.keySet()) {
countMap.put(v, new int[] {0});
}
- for (DefaultDirectedGraph.VertexInfo<V, E> info
- : graph.vertexMap.values()) {
- for (E edge : info.outEdges) {
- //noinspection SuspiciousMethodCalls
- final int[] ints =
- requireNonNull(countMap.get(edge.target),
- () -> "no value for " + edge.target);
- ++ints[0];
+ if (hepMatchOrder == HepMatchOrder.TOP_DOWN) {
+ for (DefaultDirectedGraph.VertexInfo<V, E> info
+ : graph.vertexMap.values()) {
+ for (E edge : info.outEdges) {
+ //noinspection SuspiciousMethodCalls
+ final int[] ints =
+ requireNonNull(countMap.get(edge.target),
+ () -> "no value for " + edge.target);
+ ++ints[0];
+ }
+ }
+ }
+ if (hepMatchOrder == HepMatchOrder.BOTTOM_UP) {
+ for (DefaultDirectedGraph.VertexInfo<V, E> info
+ : graph.vertexMap.values()) {
+ for (E edge : info.outEdges) {
+ //noinspection SuspiciousMethodCalls
+ final int[] ints =
+ requireNonNull(countMap.get(edge.source),
+ () -> "no value for " + edge.source);
+ ++ints[0];
+ }
}
}
for (Map.Entry<V, int[]> entry : countMap.entrySet()) {
@@ -84,15 +112,30 @@ private void populate(
DefaultDirectedGraph.VertexInfo<V, E> vertexInfo =
requireNonNull(graph.vertexMap.get(v),
() -> "no vertex " + v);
- for (E o : vertexInfo.outEdges) {
- //noinspection unchecked
- final V target = (V) o.target;
- int[] ints =
- requireNonNull(countMap.get(target),
- () -> "no counts found for target " + target);
- if (--ints[0] == 0) {
- countMap.remove(target);
- empties.add(target);
+ if (hepMatchOrder == HepMatchOrder.TOP_DOWN) {
+ for (E o : vertexInfo.outEdges) {
+ //noinspection unchecked
+ final V target = (V) o.target;
+ int[] ints =
+ requireNonNull(countMap.get(target),
+ () -> "no counts found for target " + target);
+ if (--ints[0] == 0) {
+ countMap.remove(target);
+ empties.add(target);
+ }
+ }
+ }
+ if (hepMatchOrder == HepMatchOrder.BOTTOM_UP) {
+ for (E o : vertexInfo.inEdges) {
+ //noinspection unchecked
+ final V source = (V) o.source;
+ int[] ints =
+ requireNonNull(countMap.get(source),
+ () -> "no counts found for source " + source);
+ if (--ints[0] == 0) {
+ countMap.remove(source);
+ empties.add(source);
+ }
}
}
return v;
diff --git
a/core/src/test/java/org/apache/calcite/util/graph/DirectedGraphTest.java
b/core/src/test/java/org/apache/calcite/util/graph/DirectedGraphTest.java
index 1425c40dd0..dae679bdad 100644
--- a/core/src/test/java/org/apache/calcite/util/graph/DirectedGraphTest.java
+++ b/core/src/test/java/org/apache/calcite/util/graph/DirectedGraphTest.java
@@ -15,6 +15,8 @@
* limitations under the License.
*/
package org.apache.calcite.util.graph;
+import org.apache.calcite.plan.hep.HepMatchOrder;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
@@ -172,6 +174,19 @@ private <V> List<List<V>> paths(DirectedGraph<V,
DefaultEdge> g,
assertThat(list, hasToString("[A, B, E, C, F, D]"));
}
+ /**
+ * Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7030">[CALCITE-7030]
+ * Enhance TopologicalOrderIterator to support BOTTOM_UP</a>. */
+ @Test void testTopologicalOrderWithBottomUpIterator() {
+ final DefaultDirectedGraph<String, DefaultEdge> graph = createDag();
+ final List<String> list = new ArrayList<>();
+ for (String s : TopologicalOrderIterator.of(graph,
HepMatchOrder.BOTTOM_UP)) {
+ list.add(s);
+ }
+ assertThat(list, hasToString("[D, F, C, B, E, A]"));
+ }
+
private DefaultDirectedGraph<String, DefaultEdge> createDag() {
// D F
// ^ ^