/******************************************************************************* * Copyright 2012 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.util.test; import static java.util.Objects.*; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; import java.util.HashMap; import java.util.Map.Entry; import java.util.Objects; import java.util.Random; import java.util.TreeMap; import org.eclipse.jdt.annotation.Nullable; import com.analog.lyric.dimple.environment.DimpleEnvironment; import com.analog.lyric.dimple.exceptions.DimpleException; import com.analog.lyric.dimple.factorfunctions.XorDelta; import com.analog.lyric.dimple.factorfunctions.core.TableFactorFunction; import com.analog.lyric.dimple.model.core.FactorGraph; import com.analog.lyric.dimple.model.core.FactorGraphIterables; import com.analog.lyric.dimple.model.core.INode; import com.analog.lyric.dimple.model.core.Port; import com.analog.lyric.dimple.model.domains.DiscreteDomain; import com.analog.lyric.dimple.model.domains.IntRangeDomain; import com.analog.lyric.dimple.model.factors.Factor; import com.analog.lyric.dimple.model.factors.FactorList; import com.analog.lyric.dimple.model.variables.Discrete; import com.analog.lyric.dimple.model.variables.Variable; import com.analog.lyric.dimple.model.variables.VariableList; import com.analog.lyric.dimple.schedulers.schedule.ISchedule; import com.analog.lyric.dimple.solvers.core.parameterizedMessages.DiscreteWeightMessage; import com.analog.lyric.dimple.solvers.interfaces.IFactorGraphFactory; import com.analog.lyric.util.misc.Internal; import com.google.common.base.Strings; /** * @category internal */ @Internal public class Helpers { static public Random _r = new Random(); final static public double EPSILON = 0.00001; static public FactorGraph MakeSimpleThreeLevelGraph() { return MakeSimpleThreeLevelGraph(DimpleEnvironment.active().defaultSolver()); } static public FactorGraph MakeSimpleThreeLevelGraph(@Nullable IFactorGraphFactory<?> graphFactory) { return MakeSimpleThreeLevelGraphs(graphFactory)[0]; } static public FactorGraph MakeSimpleGraph(String tag, @Nullable IFactorGraphFactory<?> graphFactory, boolean randomPrior) { Discrete vB1 = new Discrete(0.0, 1.0); Discrete vO1 = new Discrete(0.0, 1.0); Discrete vO2 = new Discrete(0.0, 1.0); vB1.setName(String.format("v%sB1", tag)); vO1.setName(String.format("v%sO1", tag)); vO2.setName(String.format("v%sO2", tag)); FactorGraph fg = new FactorGraph(vB1); fg.setName(tag); fg.setSolverFactory(graphFactory); Factor f = fg.addFactor(new XorDelta(), vB1, vO1, vO2); f.setName(String.format("f%s", tag)); if (randomPrior) { VariableList variables = fg.getVariables(); double[][] trivialRandomCodeword = trivialRandomCodeword(variables.size()); for(int variable = 0; variable < variables.size(); ++variable) { ((Discrete)variables.getByIndex(variable)).setPrior(trivialRandomCodeword[variable]); } } return fg; } static public FactorGraph MakeSimpleGraph(String tag) { return MakeSimpleGraph(tag, DimpleEnvironment.active().defaultSolver(), false); } static public FactorGraph MakeSimpleChainGraph( String tag, @Nullable IFactorGraphFactory<?> graphFactory, int factors, boolean randomPrior) { FactorGraph fg = new FactorGraph(); fg.setSolverFactory(graphFactory); fg.setName(tag); Discrete[] discretes = new Discrete[factors + 1]; for(int variable = 0; variable < discretes.length; ++variable) { discretes[variable] = new Discrete(0.0, 1.0); } XorDelta xorFF = new XorDelta(); for(int factor = 0; factor < factors; ++factor) { fg.addFactor(xorFF, discretes[factor], discretes[factor + 1]); } Helpers.setNamesByStructure(fg); if (randomPrior) { VariableList variables = fg.getVariables(); double[][] trivialRandomCodeword = trivialRandomCodeword(variables.size()); for(int variable = 0; variable < variables.size(); ++variable) { ((Discrete)variables.getByIndex(variable)).setPrior(trivialRandomCodeword[variable]); } } return fg; } static public FactorGraph MakeSimpleLoopyGraph( String tag, @Nullable IFactorGraphFactory<?> graphFactory, boolean randomInput) { DimpleEnvironment env = DimpleEnvironment.active(); IFactorGraphFactory<?> oldFactory = env.setDefaultSolver(graphFactory); FactorGraph fg = null; Discrete vB1 = new Discrete(0.0, 1.0); Discrete vO1 = new Discrete(0.0, 1.0); Discrete vO2 = new Discrete(0.0, 1.0); vB1.setName(String.format("v%sB1", tag)); vO1.setName(String.format("v%sO1", tag)); vO2.setName(String.format("v%sO2", tag)); fg = new FactorGraph(vB1); fg.setName(tag); XorDelta xorFF = new XorDelta(); Factor f1 = fg.addFactor(xorFF, vB1, vO1, vO2); f1.setName(String.format("f1%s", tag)); Discrete vO3 = new Discrete(0.0, 1.0); Discrete vO4 = new Discrete(0.0, 1.0); vO3.setName(String.format("v%sO3", tag)); vO4.setName(String.format("v%sO4", tag)); Factor f2 = fg.addFactor(xorFF, vO2, vO3, vO4); f2.setName(String.format("f2%s", tag)); Discrete vO5 = new Discrete(0.0, 1.0); vO5.setName(String.format("v%sO5", tag)); Factor f3 = fg.addFactor(xorFF, vO3, vO5, vO1); f3.setName(String.format("f3%s", tag)); if(randomInput) { VariableList variables = fg.getVariables(); double[][] trivialRandomCodeword = trivialRandomCodeword(variables.size()); for(int variable = 0; variable < variables.size(); ++variable) { ((Discrete)variables.getByIndex(variable)).setPrior(trivialRandomCodeword[variable]); } } env.setDefaultSolver(oldFactory); return fg; } static public FactorGraph[] MakeSimpleThreeLevelGraphs() { return MakeSimpleThreeLevelGraphs(DimpleEnvironment.active().defaultSolver()); } static public FactorGraph[] MakeSimpleThreeLevelGraphs(@Nullable IFactorGraphFactory<?> factory) { Discrete vRootB1 = new Discrete(0.0, 1.0); Discrete vRootO1 = new Discrete(0.0, 1.0); Discrete vRootO2 = new Discrete(0.0, 1.0); Discrete vMidB1 = new Discrete(0.0, 1.0); Discrete vMidO1 = new Discrete(0.0, 1.0); Discrete vMidO2 = new Discrete(0.0, 1.0); Discrete vLeafB1 = new Discrete(0.0, 1.0); Discrete vLeafO1 = new Discrete(0.0, 1.0); Discrete vLeafO2 = new Discrete(0.0, 1.0); vRootB1.setName("vRootB1"); vRootO1.setName("vRootO1"); vRootO2.setName("vRootO2"); vMidB1.setName("vMidB1"); vMidO1.setName("vMidO1"); vMidO2.setName("vMidO2"); vLeafB1.setName("vLeafB1"); vLeafO1.setName("vLeafO1"); vLeafO2.setName("vLeafO2"); FactorGraph fgRoot = new FactorGraph(vRootB1); FactorGraph fgMid = new FactorGraph(vMidB1); FactorGraph fgLeaf = new FactorGraph(vLeafB1); fgRoot.setSolverFactory(factory); fgMid.setSolverFactory(factory); fgLeaf.setSolverFactory(factory); fgRoot.setName("Root"); fgMid.setName("Mid"); fgLeaf.setName("Leaf"); XorDelta xorFF = new XorDelta(); Factor fRoot = fgRoot.addFactor(xorFF, vRootB1, vRootO1, vRootO2); Factor fMid = fgMid.addFactor( xorFF, vMidB1, vMidO1, vMidO2); Factor fLeaf = fgLeaf.addFactor(xorFF, vLeafB1, vLeafO1, vLeafO2); fRoot.setName("fRoot"); fMid.setName("fMid"); fLeaf.setName("fLeaf"); //One sub graph fgMid.addGraph(fgLeaf, vMidO2); //Two sub graphs fgRoot.addGraph(fgMid, vRootO2); return new FactorGraph[]{fgRoot, fgMid, fgLeaf}; } static public double compareBeliefs(double[][] a, double[][] b) { return compareBeliefs(a, b, EPSILON); } static public double compareBeliefs(double[][] a, double[][] b, String tag) { return compareBeliefs(a, b, EPSILON, false, tag); } static public double compareBeliefs(double[][] a, double[][] b, double epsilon) { return compareBeliefs(a, b, epsilon, false); } static public double compareBeliefs(double[][] a, double[][] b, double epsilon, String tag) { return compareBeliefs(a, b, epsilon, false, tag); } static public double compareBeliefs(double[][] a, double[][] b, double epsilon, boolean shouldBeSomeMismatch) { return compareBeliefs(a, b, epsilon, shouldBeSomeMismatch, "kaboom"); } static public double compareBeliefs(double[][] a, double[][] b, double epsilon, boolean shouldBeSomeMismatch, String tag) { double diffSum = 0; int diffs = 0; boolean same = a.length == b.length; if(!same) { System.out.println(String.format("ERROR in compareBeliefs: a.length(%d) != b.length (%d), [%s]", a.length, b.length, tag)); } assertTrue(tag, same); for(int i = 0; i < a.length; ++i) { same = a[i].length == b[i].length; if(!same) { System.out.println(String.format("ERROR in compareBeliefs: a[i].length(%d) != b[i].length(%d), i:%d, [%s]", a[i].length, b[i].length, i, tag)); } assertTrue(tag, same); for(int j = 0; j < a[i].length; ++j) { double diff = Math.abs(a[i][j] - b[i][j]); diffSum += diff; same = diff < epsilon; if(!same) { diffs++; if(!shouldBeSomeMismatch) { System.out.println(String.format("ERROR in compareBeliefs: i:%d j:%d a[i][j]:%f b[i][j]:%f a[i][j] - b[i][j]:%f abs:%f epsilon:%f [%s]" ,i ,j ,a[i][j] ,b[i][j] ,a[i][j]-b[i][j] ,Math.abs(a[i][j] - b[i][j]) ,epsilon ,tag)); } } if(!shouldBeSomeMismatch) { assertTrue(tag, same); } } } if(shouldBeSomeMismatch) { if(diffs == 0) { System.out.println(String.format("Expecting at least one mismatch, got 0 > epislon. diffSum:%f epsilon:%f [%s]", diffSum, epsilon, tag)); } assertTrue(tag, diffs > 0); } return diffSum; } static public void setInputs(FactorGraph fg, double[][] inputs) { VariableList vs = fg.getVariables(); for(int i = 0; i < vs.size(); ++i) { Discrete d = (Discrete) vs.getByIndex(i); d.setPrior(inputs[i]); } } static public double assertBeliefsDifferent(double[][] a, double[][] b) { return compareBeliefs(a, b, EPSILON, true); } static public double[][] beliefs(FactorGraph fg) { return beliefsOrInputs(fg, false, false, true, true); } static public double[][] inputs(FactorGraph fg) { return beliefsOrInputs(fg, false, false, true, false); } static public double[][] beliefs(FactorGraph fg, boolean byName) { return beliefsOrInputs(fg, byName, false, false, true); } static public double[][] beliefs(FactorGraph fg, boolean byName, boolean print) { return beliefsOrInputs(fg, byName, print, false, true); } static public double[][] beliefsOrInputs(FactorGraph fg, boolean byName, boolean print, boolean byAddOrder, boolean getbeliefs) { VariableList vs = fg.getVariables(); Collection<? extends Variable> vars = vs.values(); double[][] ret = new double[vs.size()][]; if (!byAddOrder) { TreeMap<String, Discrete> vsSorted = new TreeMap<String, Discrete>(); for(int i = 0; i < vs.size(); ++i) { String sortBy = vs.getByIndex(i).getQualifiedName(); if(!byName) { sortBy = vs.getByIndex(i).getUUID().toString(); } vsSorted.put(sortBy, (Discrete)(vs.getByIndex(i))); } vars = vsSorted.values(); } int i = 0; for(Variable var : vars) { Discrete d = (Discrete)var; if (getbeliefs) { ret[i] = d.getBelief(); } else { ret[i] = new DiscreteWeightMessage(d.getDomain(), d.getPrior()).representation(); } if (print) { StringBuilder sb = new StringBuilder(); sb.append("["); sb.append(d.getLabel()); sb.append("]: {" ); double[] oneVariablesRet = requireNonNull(ret[i]); for(int j = 0; j < oneVariablesRet.length; j++) { sb.append(((Double)oneVariablesRet[j]).toString()); if(j < oneVariablesRet.length - 1) { sb.append(" "); } } sb.append("}"); System.out.println(sb.toString()); } i++; } return ret; } static public double compareBeliefs(FactorGraph fgA, FactorGraph fgB) { return compareBeliefs(fgA, fgB, true, EPSILON); } static public double compareBeliefs(FactorGraph fgA, FactorGraph fgB, double epsilon) { return compareBeliefs(fgA, fgB, true, epsilon); } static public double compareBeliefs(FactorGraph fgA, FactorGraph fgB, boolean byName) { return compareBeliefs(fgA, fgB, byName, EPSILON); } static public double compareBeliefs(FactorGraph fgA, FactorGraph fgB, boolean byName, double epsilon) { double[][] beliefsA = beliefs(fgA, byName); double[][] beliefsB = beliefs(fgB, byName); return compareBeliefs(beliefsA, beliefsB, epsilon); } public static String getBeliefString(INode node) { StringBuilder sb = new StringBuilder(); ArrayList<Discrete> variables = new ArrayList<Discrete>(); if(node instanceof Discrete) { for(Port p : node.getPorts()) { for(Port p2 : p.getSiblingNode().getPorts()) { variables.add((Discrete) p2.getSiblingNode()); } } } else { for(Port p : node.getPorts()) { variables.add((Discrete) p.getSiblingNode()); } } for(Discrete mv : variables) { getBeliefString(sb, mv); } return sb.toString(); } public static void getBeliefString(StringBuilder sb, Discrete variable) { try { double[] belief = requireNonNull(variable.getBelief()); sb.append(" {" ); for(int j = 0; j < belief.length; j++) { sb.append(((Double)belief[j]).toString()); if(j < belief.length - 1) { sb.append(" "); } } sb.append("}"); } catch(Exception e) { } } public static void printDifferences(String tag, double[][] a, double[][] b) { double epsilon = 0.00001; boolean same = a.length == b.length; if(!same) { throw new DimpleException(String.format("ERROR in check: a.length(%d) != b.length (%d)", a.length, b.length)); } for(int i = 0; i < a.length; ++i) { same = a[i].length == b[i].length; if(!same) { throw new DimpleException(String.format("ERROR in compareBeliefs: a[i].length(%d) != b[i].length(%d), i:%d", a[i].length, b[i].length, i)); } for(int j = 0; j < a[i].length; ++j) { if(Math.abs(a[i][j] - b[i][j]) > epsilon) { same = false; } } } if(!same) { StringBuilder sb = new StringBuilder(String.format("check [%s]\n", tag)); for(int i = 0; i < a.length; ++i) { sb.append(String.format("\ta%3d ", i)); for(int j = 0; j < a[i].length; ++j) { sb.append(" "); sb.append(((Double)a[i][j]).toString()); } sb.append("\n"); sb.append(String.format("\tb%3d ", i)); for(int j = 0; j < b[i].length; ++j) { sb.append(" "); sb.append(((Double)b[i][j]).toString()); } sb.append("\n"); } System.out.println(sb.toString()); } } static public double[][] trivialDeepCopy(double[][] x) { double[][] copy = new double[x.length][]; for(int i = 0; i < copy.length; ++i) { copy[i] = new double[x[i].length]; for(int j = 0; j < x[i].length; ++j) { copy[i][j] = x[i][j]; } } return copy; } static public double[][] zerosCodeWord(int length, int numErrors) { return zerosCodeWord(length, numErrors, 0.99999); } static public double[][] zerosCodeWord(int length, int numErrors, double confidence) { if(numErrors > length) { throw new DimpleException("more error bits than bits is silly"); } double[][] codeWord = new double[length][]; for(int i = 0; i < codeWord.length; i++) { codeWord[i] = new double[2]; codeWord[i][0] = 1 - confidence; codeWord[i][1] = confidence; } for(int i = 0; i < numErrors; ++i) { int errorIdx = _r.nextInt(codeWord.length); double temp = codeWord[errorIdx][0]; codeWord[errorIdx][0] = codeWord[errorIdx][1]; codeWord[errorIdx][1] = temp; } return codeWord; } static public double[][] trivialRandomCodeword(int length) { double[][] codeWord = new double[length][]; for(int i = 0; i < codeWord.length; i++) { codeWord[i] = new double[2]; codeWord[i][0] = _r.nextDouble(); codeWord[i][1] = 1 - codeWord[i][0]; } return codeWord; } static @Nullable Variable[] ordered_vars; @SuppressWarnings("deprecation") public static void initFgForDecode(FactorGraph fg, IFactorGraphFactory<?> solver, ISchedule schedule, int iterations) { fg.setSolverFactory(solver); fg.setSchedule(schedule); requireNonNull(fg.getSolver()).setNumIterations(iterations); } public static double[][] decodeGeneralCodeword( double[][] codewordWithErrors, FactorGraph fg) //int iterations, //IFactorGraphFactory solver, //ISchedule schedule) // ) { // if (!didInits) { // fg.setSolverFactory(solver); // fg.setSchedule(schedule); // fg.getSolver().setNumIterations(iterations); // didInits = true; // } VariableList variables = fg.getVariables(); Variable namedVar = fg.getVariableByName("order_vv0"); // Some graphs have explicitNames of "order_vv#" so that this routine can work on // graphs such as fec boolean hasOrderNames = (namedVar != null); if (hasOrderNames && ordered_vars == null) { final Variable[] vars = ordered_vars = new Variable[variables.size()]; for(int i = 0; i < variables.size(); ++i) { Variable thisVar; String orderName = "order_vv" + i; thisVar = fg.getVariableByName(orderName); vars[i] = thisVar; } } for(int i = 0; i < variables.size(); ++i) { Variable thisVar; if (hasOrderNames) { //String orderName = "order_vv" + i; //thisVar = fg.getVariableByName(orderName); thisVar = Objects.requireNonNull(ordered_vars)[i]; } else { thisVar = variables.getByIndex(i); } ((Discrete)thisVar).setPrior(codewordWithErrors[i]); //((Discrete)variables.getByIndex(i)).setPrior(codewordWithErrors[i]); } fg.solve(); //Verify we decoded! VariableList vs = fg.getVariables(); double[][] beliefs = new double[vs.size()][]; for(int i = 0; i < vs.size(); ++i) { Variable thisVar; if (hasOrderNames) { //String orderName = "order_vv" + i; //thisVar = fg.getVariableByName(orderName); thisVar = Objects.requireNonNull(ordered_vars)[i]; } else { thisVar = variables.getByIndex(i); } beliefs[i] = (double[]) ((Discrete)thisVar).getBeliefObject(); //beliefs[i] = (double[]) ((Discrete)vs.getByIndex(i)).getBeliefObject(); } return beliefs; } static public IntRangeDomain domainFromRange(int first, int last) { if(first >= last) { throw new DimpleException(String.format("first (%d) must be less than last (%d)", first, last)); } return DiscreteDomain.range(first, last); } static public Factor addSillyFactor(FactorGraph fg, int rows, Object[] variables) { return addSillyFactor(fg, rows, variables, false); } static public Factor addSillyFactor(FactorGraph fg, int rows, Object[] variables, boolean randomWeights) { AlwaysTrueUpToNRowsFactorFunction atff = new AlwaysTrueUpToNRowsFactorFunction(rows, randomWeights); Factor f = fg.addFactor(atff, variables); return f; } static public TableFactorFunction createSillyTable(int rows, int columns) { int[][] dummyTable = new int[rows][columns]; for(int i = 0; i < dummyTable.length; ++i) { BitSet bits = new BitSet(16); int index = 0; int value = i + 1; while (value != 0) { if ((value & 1) != 0) { bits.set(index); } ++index; value = value >>> 1; } for(int j = 0; j < dummyTable[i].length; ++j) { dummyTable[i][j] = bits.get(j) ? 0 : 1; } } double[] dummyValues = new double[rows]; Arrays.fill(dummyValues, 1.0); DiscreteDomain[] domains = new DiscreteDomain[columns]; Arrays.fill(domains, DiscreteDomain.bit()); return new TableFactorFunction("silly", dummyTable, dummyValues, domains); } static public void setSeed(long seed) { _r.setSeed(seed); } static public void clearNames(FactorGraph root) { for (FactorGraph fg : FactorGraphIterables.subgraphs(root)) { fg.setName(null); for (Variable v : fg.getOwnedVariables()) { v.setName(null); } for (Factor f : fg.getOwnedFactors()) { f.setName(null); } } } static public void setNamesByStructure(FactorGraph fg) { setNamesByStructure(fg, "bv", "v", "f", "graph", "subGraph"); } static public void setNamesByStructure(FactorGraph fg,String boundaryString, String ownedString, String factorString, String rootGraphString, String childGraphString) { int i; // If root, set boundary variables if (!fg.hasParentGraph()) { i = 0; for (Variable v : FactorGraphIterables.boundary(fg)) { v.setName(String.format("%s%d", boundaryString, i)); ++i; } if (fg.getExplicitName() != null) { fg.setName(rootGraphString); } } i = 0; for (Variable v : fg.getOwnedVariables()) { v.setName(String.format("%s%d", ownedString, i)); ++i; } i = 0; for (Factor f : fg.getOwnedFactors()) { f.setName(String.format("%s%d", factorString, i)); ++i; } i = 0; for (FactorGraph subgraph : fg.getOwnedGraphs()) { subgraph.setName(String.format("%s%d", childGraphString, i)); setNamesByStructure(subgraph, boundaryString, ownedString, factorString, rootGraphString, childGraphString); ++i; } } public static String getAdjacencyString(FactorGraph fg) { StringBuilder sb = new StringBuilder("------Adjacency------\n"); FactorList allFunctions = fg.getNonGraphFactors(); sb.append(String.format("\n--Functions (%d)--\n", allFunctions.size())); for(Factor fn : allFunctions) { String fnName = fn.getLabel(); final FactorGraph fnParent = requireNonNull(fn.getParentGraph()); if(fnParent.getParentGraph() != null) { fnName = fn.getQualifiedLabel(); } sb.append(String.format("fn [%s]\n", fnName)); for(int i = 0, end = fn.getSiblingCount(); i < end; i++) { Variable v = fn.getSibling(i); String vName = v.getLabel(); final FactorGraph vParent = v.getParentGraph(); if (vParent != null && // can happen with boundary variables vParent.getParentGraph() != null) { vName = v.getQualifiedLabel(); } sb.append(String.format("\t-> [%s]\n", vName)); } } VariableList allVariables = fg.getVariables(); sb.append(String.format("--Variables (%d)--\n", allVariables.size())); for(Variable v : allVariables) { String vName = v.getLabel(); final FactorGraph vParent = v.getParentGraph(); if(vParent != null && //can happen with boundary variables vParent.getParentGraph() != null) { vName = v.getQualifiedLabel(); } sb.append(String.format("var [%s]\n", vName)); for(int i = 0, end = v.getSiblingCount(); i < end; i++) { Factor fn = v.getFactors()[i]; String fnName = fn.getLabel(); final FactorGraph fnParent = requireNonNull(fn.getParentGraph()); if(fnParent.getParentGraph() != null) { fnName = fn.getQualifiedLabel(); } sb.append(String.format("\t-> [%s]\n", fnName)); } } return sb.toString(); } public static String getDegreeString(FactorGraph fg) { StringBuilder sb = new StringBuilder("------Degrees------\n"); HashMap<Integer, ArrayList<INode>> variablesByDegree = getVariablesByDegree(fg); HashMap<Integer, ArrayList<INode>> factorsByDegree = getFactorsByDegree(fg); sb.append("Variables:\n"); for(Entry<Integer, ArrayList<INode>> entry : variablesByDegree.entrySet()) { sb.append(String.format("\tdegree:%02d count:%03d\n", entry.getKey(), entry.getValue().size())); } sb.append("Factors:\n"); for(Entry<Integer, ArrayList<INode>> entry : factorsByDegree.entrySet()) { sb.append(String.format("\tdegree:%02d count:%03d\n", entry.getKey(), entry.getValue().size())); } sb.append("-------------------\n"); return sb.toString(); } public static String getDomainSizeString(FactorGraph fg) { StringBuilder sb = new StringBuilder("------Domains------\n"); TreeMap<Integer, ArrayList<Variable>> variablesByDomain = getVariablesByDomainSize(fg); for(Entry<Integer, ArrayList<Variable>> entry : variablesByDomain.entrySet()) { sb.append(String.format("\tdomain:[%03d] count:%03d\n", entry.getKey(), entry.getValue().size())); } sb.append("-------------------\n"); return sb.toString(); } public static String getDomainString(FactorGraph fg) { StringBuilder sb = new StringBuilder("------Domains------\n"); TreeMap<Integer, ArrayList<Variable>> variablesByDomain = getVariablesByDomainSize(fg); for(Entry<Integer, ArrayList<Variable>> entry : variablesByDomain.entrySet()) { for(Variable vb : entry.getValue()) { sb.append(String.format("\t[%-20s] Domain [%-40s]\n", vb.getLabel(), vb.getDomain().toString())); } } sb.append("-------------------\n"); return sb.toString(); } public static String getFullString(FactorGraph fg) { StringBuilder sb = new StringBuilder(fg.toString() + "\n"); sb.append(getNodeString(fg)); sb.append(getAdjacencyString(fg)); sb.append(getDegreeString(fg)); return sb.toString(); } public static String getNodeString(FactorGraph fg) { return getNodeString(fg, 0); } private static String getNodeString(FactorGraph fg, int tabDepth) { String tabString = Strings.repeat("\t", tabDepth); //graph itself StringBuilder sb = new StringBuilder(tabString + "------Nodes------\n"); //functions sb.append(tabString); // sb.append("Functions:\n"); for(Factor fn : fg.getOwnedFactors()) { sb.append(tabString); sb.append("\t"); sb.append(fn.getQualifiedLabel()); sb.append("\n"); } //boundary variables sb.append(tabString); sb.append("Boundary variables:\n"); for (Variable v : FactorGraphIterables.boundary(fg)) { sb.append(tabString); sb.append("\t"); sb.append(v.getQualifiedLabel()); sb.append("\n"); } //owned variables sb.append(tabString); sb.append("Owned variables:\n"); for(Variable v : fg.getOwnedVariables()) { sb.append(tabString); sb.append("\t"); sb.append(v.getQualifiedLabel()); sb.append("\n"); } //child graphs sb.append(tabString); sb.append("Sub graphs:\n"); for(FactorGraph g : fg.getOwnedGraphs()) { sb.append(tabString); sb.append(g.toString()); sb.append("\n"); sb.append(getNodeString(g, tabDepth + 1)); } return sb.toString(); } static public HashMap<Integer, ArrayList<INode>> getNodesByDegree(ArrayList<INode> nodes) { HashMap<Integer, ArrayList<INode>> nodesByDegree = new HashMap<Integer, ArrayList<INode>>(); for(INode node : nodes) { int degree = node.getSiblingCount(); if(!nodesByDegree.containsKey(degree)) { ArrayList<INode> degreeNNodes = new ArrayList<INode>(); nodesByDegree.put(degree, degreeNNodes); } nodesByDegree.get(degree).add(node); } return nodesByDegree; } public static HashMap<Integer, ArrayList<INode>> getNodesByDegree(FactorGraph fg) { ArrayList<INode> nodes = new ArrayList<INode>(); nodes.addAll(fg.getNonGraphFactors()); nodes.addAll(fg.getVariables()); return getNodesByDegree(nodes); } public static HashMap<Integer, ArrayList<INode>> getVariablesByDegree(FactorGraph fg) { ArrayList<INode> nodes = new ArrayList<INode>(); nodes.addAll(fg.getVariables()); return getNodesByDegree(nodes); } public static HashMap<Integer, ArrayList<INode>> getFactorsByDegree(FactorGraph fg) { ArrayList<INode> nodes = new ArrayList<INode>(); nodes.addAll(fg.getNonGraphFactors()); return getNodesByDegree(nodes); } public static TreeMap<Integer, ArrayList<Variable>> getVariablesByDomainSize(FactorGraph fg) { ArrayList<Variable> variables = new ArrayList<Variable>(); variables.addAll(fg.getVariables()); TreeMap<Integer, ArrayList<Variable>> variablesByDomain = new TreeMap<Integer, ArrayList<Variable>>(); for(Variable vb : variables) { if(!(vb.getDomain() instanceof DiscreteDomain)) { throw new DimpleException("whoops"); } DiscreteDomain domain = (DiscreteDomain) vb.getDomain(); int size = domain.size(); if(!variablesByDomain.containsKey(size)) { ArrayList<Variable> variablesForDomain = new ArrayList<Variable>(); variablesByDomain.put(size, variablesForDomain); } variablesByDomain.get(size).add(vb); } return variablesByDomain; } }