📄 undirectedmodel.java
字号:
} catch (Exception e) { e.printStackTrace(); } } /** * Adds an edge with its edge potential at the same time. * <P> * SINGLE ARRAY ORDER DISCUSSION. * @param var1 One variable in the edge * @param var2 Andother variable of the edge * @param probs A one-dimensional array that specifies the * potential for the new edge. The size of the array must be * <tt>v1.getNumOutcomes() * v2.getNumOutcomes()</tt> * @see #addEdgeWithPotential(Vertex,Vertex,DiscretePotential) */ public void addEdgeWithPotential (Variable var1, Variable var2, double[] probs) { try { /* This is broken. salvo,jesus.graph.Graph.addEdge() should *not* * declare itself as throwing java.lang.Exception. Come on! */ Edge e = addEdge (var1, var2); Clique c = new HashClique (e); MultinomialPotential pot = new MultinomialPotential (new Variable[] { var1, var2 }, probs); addPotential (c, pot); } catch (Exception e) { e.printStackTrace(); } } /** * Adds a potential to the model. * <P> * If a potential has already been added for the variables in the * given clique, the effects of this method are (currently) * undefined. * * @param clique The set of variables which the potential is over. * These variables must form a clique in the graph, i.e., * each pair of variables in <tt>clique</tt> must be adjacent. * This method does not add those edges automatically. * @param potential A potential over the variables in clique. * This potential must be defined over the variables in <tt>clique</tt>. */ public void addPotential (Clique clique, DiscretePotential potential) { potentials.put (clique, potential); // cache the potential cachePotential(clique, potential); } private void cachePotential (Clique clique, DiscretePotential potential) { switch (clique.size()) { case 1: vertexPots [getIndex (clique.get(0))] = potential; break; case 2: int idx1 = getIndex (clique.get(0)); int idx2 = getIndex (clique.get(1)); cacheEdgePtl (idx1, idx2, potential); break; default: break; } } private void cacheEdgePtl(int idx1, int idx2, DiscretePotential ptl) { assert (idx1 < 65536) && (idx2 < 65536); int id; if (idx1 < idx2) { id = (idx1 << 16) | idx2; } else { id = (idx2 << 16) | idx1; } edgePots.put (id, ptl); } /** * Adds a node potential. This method has exactly the * same effect as calling {@link * #addPotential(Clique,DiscretePotential)} with a Clique * object that contains only <tt>var</tt>. * <P> * If a potential has already been added for this node * the effects of this method are (currently) undefined. * * @param var Variables which the potential is over. * @param pot A potential defined over <tt>var</tt>. * This potential must be defined over the variables in <tt>clique</tt>. */ public void addPotential (Variable var, DiscretePotential pot) { Clique c = new HashClique(); c.add (var); addPotential (c, pot); } /** * Removes all potentias from this model. */ public void clearPotentials () { potentials.clear (); vertexPots = new DiscretePotential [numNodes]; edgePots.clear(); } /** * Returns the potential for a given clique. * @return The potential defined over this clique. Returns null if * no such potential exists. Will not return * potential defined over subsets or supersets of this clique. * @see #addPotential(Clique,DiscretePotential) * @see #potentialOfEdge(Vertex,Vertex) * @see #potentialOfVertex(Vertex) */ public DiscretePotential potentialOfClique (Clique clique) { switch (clique.size ()) { case 1: return potentialOfVertex (clique.get (0)); case 2: return potentialOfEdge (clique.get (0), clique.get (1)); default: return potentialOfCollection (clique); } } /** * Returns the potential for a given edge. * <P> * This method is equivalent to calling {@link potentialOfClique} * with a clique object that contains only <tt>v1</tt> and <tt>v2</tt>. * <P> * @param v1 One variable of the edge. * @param v2 The other variable of the edge. * @return The potential defined over the edge <tt>(v1, v2)</tt> * (such as by {@link * #addEdgeWithPotential(Vertex,Vertex,DiscretePotential) * addEdgeWithPotential}). * Returns null if no such potential exists. */ public DiscretePotential potentialOfEdge (Vertex v1, Vertex v2) { Variable var1 = (Variable) v1; Variable var2 = (Variable) v2; DiscretePotential ptl = getEdgePtl (getIndex (var1), getIndex (var2)); if (ptl != null) { assert ptl.varSet().size() == 2; assert ptl.containsVar (var1); assert ptl.containsVar (var2); } return ptl; } /** * Returns the unnormalized probability for an assignment to the * model. That is, the value return is * <pre> \prod_C \phi_C (assn)</pre>* where C ranges over all cliques for which potentials have been defined. * * @param assn An assignment for all variables in this model. * @return The unnormalized probability */ public double potentialProduct (Assignment assn) { Iterator ptlIter = potentialsIterator(); double ptlProd = 1; while (ptlIter.hasNext()) { ptlProd *= ((DiscretePotential)ptlIter.next()).phi (assn); } return ptlProd; } private DiscretePotential getEdgePtl(int idx1, int idx2) { assert (idx1 < 65536) && (idx2 < 65536); int id; if (idx1 < idx2) { id = (idx1 << 16) | idx2; } else { id = (idx2 << 16) | idx1; } return (DiscretePotential) edgePots.get (id); } /** * Returns the potential for a given node. * <P> * This method is equivalent to calling {@link potentialOfClique} * with a clique object that contains only <tt>v</tt>. This * <P> * @param v which the potential is over. * @return The potential defined over the edge <tt>v</tt> * (such as by {@link addPotential(Vertex,DiscretePotential)}). Returns null if * no such potential exists. */ public DiscretePotential potentialOfVertex (Vertex v) { Variable var = (Variable) v; return vertexPots [getIndex (var)]; } /** * Searches the graphical model for a potential over the given * collection of variables. * <P> * This metho is equivalent to calling {@link potentialOfClique} * with a clique containing the nodes in C, but that method * uses caching to be more efficient for node and edge cliques. * @return The potential defined over this clique. Returns null if * no such potential exists. Will not return * potential defined over subsets or supersets of this clique. * @see #addPotential(Clique,DiscretePotential) * @see #potentialOfClique(Clique) */ public DiscretePotential potentialOfCollection (Collection c) { for (Iterator it = potentials.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); Clique clique = (Clique) entry.getKey(); if (c.containsAll (clique) && clique.containsAll (c)) { return (DiscretePotential) entry.getValue (); } } return null; } // }}} // xxx Move to own class ??? private DiscretePotential evidencePotential (Variable var, int outcome) { double[] values = new double [var.getNumOutcomes()]; MultinomialPotential ptl = new MultinomialPotential (var, values); ptl.setPhi (new Assignment (var, outcome), 1.0); return ptl; } // xxx should be moved to GraphicalModel // xxx extremely naive implmentation // xxx destructive // xxx I'm getting a little too happy with these 'xxx's /** * Clamps a variable to an observed value. * <P> * The implementation of this method is currently destructive; that * is, the model potentials are irrevocably changed to reflect the * new evidence. Someday I might fix this. * @param var A variable in the model * @param outcome An integer outcome of var * @see #duplicate() */ public void setObserved (Variable var, int outcome) { DiscretePotential delta = evidencePotential (var, outcome); Iterator it = potentialsIterator(); while (it.hasNext()) { DiscretePotential ptl = (DiscretePotential) it.next(); if (ptl.containsVar (var)) { ptl.multiplyBy (delta); } } } public double query (Inferencer inferencer, Assignment assn) { return inferencer.query ((UndirectedModel)this, assn); } public void computeMarginals (Inferencer inferencer) { inferencer.computeMarginals (this); } /** * Returns a copy of this model. The variable objects are shared * between this model and its copy, but the potential objects are deep-copied. */ public UndirectedModel duplicate () { UndirectedModel dup = new UndirectedModel (getVerticesCount()); try { for (Iterator it = getVertexSet().iterator(); it.hasNext();) { Variable var = (Variable) it.next(); dup.add (var); } for (Iterator it = getEdgeSet().iterator(); it.hasNext();) { Edge edge = (Edge) it.next(); dup.addEdge (edge.getVertexA (), edge.getVertexB ()); } for (Iterator it = potentialsIterator(); it.hasNext();) { MultinomialPotential pot = (MultinomialPotential) it.next(); dup.addPotential (new HashClique (pot.varSet()), pot.duplicate ()); } } catch (Exception e) { e.printStackTrace (); } return dup; } /** * Dumps all the variables and potentials of the model to * <tt>System.out</tt> in human-reaable text. */ public void dump () { System.out.println(this); System.out.println("Potentials = "+potentials); for (Iterator it = potentials.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); MultinomialPotential pot = (MultinomialPotential) entry.getValue(); System.out.println(pot); } } // Caching information for various inference algorithms. THashMap inferenceCaches = new THashMap(); /** * Caches some information about this graph that is specific to * a given type of inferencer (e.g., a junction tree). * @param inferencer Class of inferencer that can use this * information * @param info The information to cache. * @see getInferenceCache */ public void setInferenceCache (Class inferencer, Object info) { inferenceCaches.put (inferencer, info); } /** * Caches some information about this graph that is specific to * a given type of inferencer (e.g., a junction tree). * @param inferencer Class of inferencer which wants the information * @return Whatever object was previously cached for inferencer * using setInferenceCache. Returns null if no object has been cached. * @see #setInferenceCache */ Object getInferenceCache (Class inferencer) { return inferenceCaches.get (inferencer); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -