/******************************************************************************* * Copyright 2014 Analog Devices, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ package com.analog.lyric.dimple.model.core; import static java.util.Objects.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.jdt.annotation.Nullable; import com.analog.lyric.collect.ReleasableIterators; import com.analog.lyric.collect.SingleIterator; import com.analog.lyric.dimple.model.factors.Factor; import com.analog.lyric.dimple.model.factors.FactorBase; import com.analog.lyric.dimple.model.variables.Constant; import com.analog.lyric.dimple.model.variables.Variable; import com.analog.lyric.dimple.model.variables.VariableBlock; import com.google.common.collect.Iterators; import com.google.common.collect.UnmodifiableIterator; /** * Contains static methods for constructing {@link Iterator}s over contents of {@link FactorGraph}s. * @since 0.08 * @author Christopher Barber * @see FactorGraphIterables */ public class FactorGraphIterators { /** * Returns iterator over the boundary variables for graph. * * @since 0.08 */ public static IFactorGraphChildIterator<Variable> boundary(FactorGraph graph) { return new BoundaryVariableIterator(graph); } /** * Returns iterator over all {@link Constant} objects contained in this graph. * <p> * Constants are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose constants will be visited. Only constants contained in this * graph or its subgraphs will be included. * @since 0.08 */ public static IFactorGraphChildIterator<Constant> constants(FactorGraph root) { return new NestedConstantIterator(root, Integer.MAX_VALUE); } /** * Returns iterator over all {@link Constant} objects contained in this graph down to specified depth below root. * <p> * Constants are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose constants will be visited. Only constants contained in this * graph or its subgraphs will be included. * @param maxNestingDepth specifies how deep in the subgraph tree to visit. If zero is specified, only * constants contained directly in the root will be included. * @since 0.08 */ public static IFactorGraphChildIterator<Constant> constantsDownto(FactorGraph root, int maxNestingDepth) { return new NestedConstantIterator(root, maxNestingDepth); } /** * Returns iterator over all {@link Factor} objects contained in this graph. * <p> * Factors are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose factors will be visited. Only factors contained in this * graph or its subgraphs will be included. * @since 0.08 */ public static IFactorGraphChildIterator<Factor> factors(FactorGraph root) { return new NestedFactorIterator(root, Integer.MAX_VALUE); } /** * Returns iterator over all {@link Factor} objects contained in this graph down to specified depth below root. * <p> * Factors are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose factors will be visited. Only factors contained in this * graph or its subgraphs will be included. * @param maxNestingDepth specifies how deep in the subgraph tree to visit. If zero is specified, only * factors contained directly in the root will be included. * @since 0.08 */ public static IFactorGraphChildIterator<Factor> factorsDownto(FactorGraph root, int maxNestingDepth) { return new NestedFactorIterator(root, maxNestingDepth); } /** * Returns iterator over all {@link Factor} and leaf {@link FactorGraph} objects contained in this graph * down to specified depth below root. * <p> * Factors are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * Subgraph objects will only be included if the maximum depth has been reached; for instance, if * {@code maxNestingDepth} is one immediate child subgraph objects will not be included but any grandchild * subgraph will be included. * <p> * @param root is the root graph whose factors will be visited. Only nodes contained in this * graph or its subgraphs will be included. * @param maxNestingDepth specifies how deep in the subgraph tree to visit. If zero is specified, only * nodes contained directly in the root will be included. * @since 0.08 */ public static IFactorGraphChildIterator<FactorBase> factorsAndLeafSubgraphsDownto(FactorGraph root, int maxNestingDepth) { return new NestedFactorBaseIterator(root, maxNestingDepth); } /** * Returns iterator over {@link Constant}s directly owned by a graph. * @since 0.08 */ public static Iterator<Constant> ownedConstants(FactorGraph graph) { return graph.ownedConstantIterator(); } /** * Returns iterator over {@link Factor}s directly owned by a graph. * @since 0.08 */ public static Iterator<Factor> ownedFactors(FactorGraph graph) { return graph.ownedFactorIterator(); } /** * Returns iterator over subgraphs directly owned by a graph. * @since 0.08 */ public static Iterator<FactorGraph> ownedSubgraphs(FactorGraph graph) { return graph.ownedGraphIterator(); } /** * Returns iterator over {@link Variable}s directly owned by a graph. * @since 0.08 */ public static Iterator<Variable> ownedVariables(FactorGraph graph) { return graph.ownedVariableIterator(); } /** * Returns iterator over {@link VariableBlock}s directly owned by a graph. * @since 0.08 */ public static Iterator<VariableBlock> ownedVariableBlocks(FactorGraph graph) { return graph.ownedVariableBlockIterator(); } /** * Returns iterator over all nested subgraphs of the root graph, including the root itself. * <p> * Subgraphs are visited in top-down order, i.e. those farther away from the root will be visited after * those closer to the root. The root itself will be the first graph returned. * <p> * @param root is the root graph whose subgraphs will be visited. Only subgraphs contained in this * graph or its subgraphs will be included. * @since 0.08 */ public static IFactorGraphChildIterator<FactorGraph> subgraphs(FactorGraph root) { return subgraphsDownto(root, Integer.MAX_VALUE); } /** * Returns iterator over all nested subgraphs of the root graph, including the root itself, down to specified depth. * <p> * Subgraphs are visited in top-down order, i.e. those farther away from the root will be visited after * those closer to the root. The root itself will be the first graph returned. * <p> * @param root is the root graph whose subgraphs will be visited. Only subgraphs contained in this * graph or its subgraphs will be included. * @param maxNestingDepth specifies how deep in the subgraph hierarchy to visit. If zero is specified, only * the root graph will be visited, if one is specified the root and its immediate subgraphs will be included. * Note that this behaves differently from how the correspondingly named argument to the other functions * in this class behaves! * @since 0.08 */ public static IFactorGraphChildIterator<FactorGraph> subgraphsDownto(FactorGraph root, int maxNestingDepth) { return new NestedFactorGraphIterator(root, maxNestingDepth); } /** * Returns iterator over all {@link Variable} objects contained in this graph. * <p> * Variable are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose variables will be visited. Only variables contained in this * graph or its subgraphs will be included. Note that boundary variables that are not owned by the root * will not be included. * @since 0.08 * @see #variablesAndBoundary(FactorGraph) */ public static IFactorGraphChildIterator<Variable> variables(FactorGraph root) { return variablesDownto(root, Integer.MAX_VALUE); } /** * Returns iterator over all {@link Variable} objects contained in this graph down to specified depth. * <p> * Variable are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose variables will be visited. Only variables contained in this * graph or its subgraphs will be included. Note that boundary variables that are not owned by the root * will not be included. * @param maxNestingDepth specifies how deep in the subgraph tree to visit. If zero is specified, only * factors contained directly in the root will be included. * @since 0.08 * @see #variablesAndBoundaryDownto(FactorGraph, int) */ public static IFactorGraphChildIterator<Variable> variablesDownto(FactorGraph root, int maxNestingDepth) { return new NestedVariableIterator(root, maxNestingDepth, false); } /** * Returns iterator over all {@link Variable} objects contained in this graph including its boundary variables. * <p> * Variable are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose variables will be visited. Only variables contained in this * graph or its subgraphs will be included. Boundary variables that are not owned by the root * will be included. * @since 0.08 * @see #variables(FactorGraph) */ public static IFactorGraphChildIterator<Variable> variablesAndBoundary(FactorGraph root) { return variablesAndBoundaryDownto(root, Integer.MAX_VALUE); } /** * Returns iterator over all {@link Variable} objects contained in this graph including its boundary variables * down to specified depth. * <p> * Variable are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose variables will be visited. Only variables contained in this * graph or its subgraphs will be included. Boundary variables that are not owned by the root * will be included. * @param maxNestingDepth specifies how deep in the subgraph tree to visit. If zero is specified, only * factors contained directly in the root will be included. * @since 0.08 * @see #variablesDownto(FactorGraph,int) */ public static IFactorGraphChildIterator<Variable> variablesAndBoundaryDownto(FactorGraph root, int maxNestingDepth) { return new NestedVariableIterator(root, maxNestingDepth, true); } /** * Returns iterator over all {@link VariableBlock}s contained in this graph. * <p> * Blocks are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose blocks will be visited. Only blocks contained in this * graph or its subgraphs will be included. * @since 0.08 */ public static IFactorGraphChildIterator<VariableBlock> variableBlocks(FactorGraph root) { return new NestedVariableBlockIterator(root, Integer.MAX_VALUE); } /** * Returns iterator over all {@link VariableBlock} objects contained in this graph down to specified depth below root. * <p> * Blocks are visited in top-down order, i.e. those in a subgraph are visited after those from their parent. * <p> * @param root is the root graph whose blocks will be visited. Only blocks contained in this * graph or its subgraphs will be included. * @param maxNestingDepth specifies how deep in the subgraph tree to visit. If zero is specified, only * constants contained directly in the root will be included. * @since 0.08 */ public static IFactorGraphChildIterator<VariableBlock> variableBlocksDownto(FactorGraph root, int maxNestingDepth) { return new NestedVariableBlockIterator(root, maxNestingDepth); } /*----------------- * Implementations */ private static class NestedFactorGraphIterator extends UnmodifiableIterator<FactorGraph> implements IFactorGraphChildIterator<FactorGraph> { private final FactorGraph _root; private final List<Iterator<FactorGraph>> _iteratorStack; private final int _maxNestingDepth; private int _lastDepth; private NestedFactorGraphIterator(FactorGraph graph, int maxNestingDepth) { _root = graph; _iteratorStack = new ArrayList<>(); _maxNestingDepth = Math.max(maxNestingDepth,0); reset(); } @Override public boolean hasNext() { for (int i = _iteratorStack.size(); --i >= 0;) { if (_iteratorStack.get(i).hasNext()) { return true; } _iteratorStack.remove(i); } return false; } @Override public @Nullable FactorGraph next() { for (int i = _iteratorStack.size(); --i >= 0;) { final FactorGraph graph = _iteratorStack.get(i).next(); if (graph != null) { _lastDepth = i; if (i < _maxNestingDepth) { _iteratorStack.add(graph.ownedGraphIterator()); } return graph; } _iteratorStack.remove(i); } _lastDepth = -1; return null; } @Override public int lastDepth() { return _lastDepth; } @Override public int maxNestingDepth() { return _maxNestingDepth; } @Override public void reset() { _iteratorStack.clear(); _iteratorStack.add(new SingleIterator<>(_root)); _lastDepth = -1; } @Override public FactorGraph root() { return _root; } } private abstract static class NestedChildIterator<T> extends UnmodifiableIterator<T> implements IFactorGraphChildIterator<T> { protected final NestedFactorGraphIterator _graphIterator; protected Iterator<? extends T> _childIterator; private NestedChildIterator(FactorGraph graph, int maxNestingDepth) { _graphIterator = new NestedFactorGraphIterator(graph, maxNestingDepth); _childIterator = ReleasableIterators.emptyIterator(); } @Override public boolean hasNext() { while (!_childIterator.hasNext()) { FactorGraph graph = _graphIterator.next(); if (graph != null) { _childIterator = childIterator(graph, _graphIterator.lastDepth()); } else { return false; } } return true; } @Override @Nullable public T next() { return hasNext() ? _childIterator.next() : null; } @Override public int lastDepth() { return _graphIterator.lastDepth(); } @Override public final int maxNestingDepth() { return _graphIterator.maxNestingDepth(); } @Override public void reset() { _graphIterator.reset(); _childIterator = childIterator(requireNonNull(_graphIterator.next()), _graphIterator.lastDepth()); } @Override public final FactorGraph root() { return _graphIterator.root(); } protected abstract Iterator<? extends T> childIterator(FactorGraph graph, int depth); } private static class NestedFactorIterator extends NestedChildIterator<Factor> { private NestedFactorIterator(FactorGraph graph, int maxNestingDepth) { super(graph, maxNestingDepth); } @Override protected Iterator<Factor> childIterator(FactorGraph graph, int depth) { return graph.ownedFactorIterator(); } } private static class NestedFactorBaseIterator extends NestedChildIterator<FactorBase> { private NestedFactorBaseIterator(FactorGraph graph, int maxNestingDepth) { super(graph, maxNestingDepth); } @Override protected Iterator<? extends FactorBase> childIterator(FactorGraph graph, int depth) { if (depth == maxNestingDepth()) { return Iterators.concat(graph.ownedFactorIterator(), graph.ownedGraphIterator()); } else { return graph.ownedFactorIterator(); } } } private static class NestedVariableIterator extends NestedChildIterator<Variable> { /** * Whether to include boundary variables at root that are not owned by the root. */ private final boolean _includeBoundary; private NestedVariableIterator(FactorGraph graph, int maxNestingDepth, boolean includeBoundary) { super(graph, maxNestingDepth); _includeBoundary = includeBoundary; } @Override protected Iterator<Variable> childIterator(FactorGraph graph, int depth) { Iterator<Variable> iterator = graph.ownedVariableIterator(); if (depth == 0 && _includeBoundary) { iterator = Iterators.concat(graph.externalBoundaryVariableIterator(), iterator); } return iterator; } } private static class BoundaryVariableIterator extends NestedChildIterator<Variable> { private BoundaryVariableIterator(FactorGraph graph) { super(graph, 0); } @Override protected Iterator<Variable> childIterator(FactorGraph graph, int depth) { return graph.boundaryVariableIterator(); } } private static class NestedConstantIterator extends NestedChildIterator<Constant> { private NestedConstantIterator(FactorGraph graph, int maxNestingDepth) { super(graph, maxNestingDepth); } @Override protected Iterator<? extends Constant> childIterator(FactorGraph graph, int depth) { return graph.ownedConstantIterator(); } } private static class NestedVariableBlockIterator extends NestedChildIterator<VariableBlock> { private NestedVariableBlockIterator(FactorGraph graph, int maxNestingDepth) { super(graph, maxNestingDepth); } @Override protected Iterator<? extends VariableBlock> childIterator(FactorGraph graph, int depth) { return graph.ownedVariableBlockIterator(); } } }