def _comparePotentials(self, pot1, pot2): """ Compare 2 potentials one in each Bayesian network Parameters ---------- pot1 : pyAgrum.Potential one of b1's cpts pot2 : pyAgrum.Potential one of _bn2's cpts Returns ------- str 'OK' if CPTs are the same Raises ------ gum.KeyError If cpts are not from the same variable """ I1 = gum.Instantiation(pot1) I2 = gum.Instantiation(pot2) I1.setFirst() while not I1.end(): I2.fromdict(I1.todict()) # copy value on the base of names if abs(pot1.get(I1) - pot2.get(I2)) > self.DELTA_ERROR: return "Different CPTs for " + pot1.variable(0).name() I1 += 1 return "OK"
def KL(p, q): """ Compute KL(p,q), Kullback-Leibler divergence :param p: gum.Potential :param q: gum.Potential :return: float """ Ip = gum.Instantiation(p) Iq = gum.Instantiation(q) s = 0 while not Ip.end(): if p.get(Ip) > 0: if q.get(Iq) > 0: s += p.get(Ip) * math.log2(p.get(Ip) / q.get(Iq)) else: s += 1 # we penalize q==0 and p>0 else: if q.get(Iq) > 0: s += 1 # we penalize q>0 and p==0 Ip.inc() Iq.inc() # it may happen that if p==q, s<0 (approximation) return 0 if s <= 0 else s
def testChainingAdd(self): bn = gum.fastBN("A->B") i = bn.completeInstantiation() m1 = gum.Instantiation().add(bn.variable("A")).add(bn.variable("B")) m2 = gum.Instantiation().add(bn.variable("B")).add(bn.variable("A")) self.assertEqual(i, m1) self.assertEqual(i, m2) m1.inc() self.assertNotEqual(i, m1) i = gum.Instantiation().addVarsFromModel(bn, ["A", "B"]) m1 = gum.Instantiation().add(bn.variable("A")).add(bn.variable("B")) m2 = gum.Instantiation().add(bn.variable("B")).add(bn.variable("A")) self.assertEqual(i, m1) self.assertEqual(i, m2) m1.inc() self.assertNotEqual(i, m1) i = gum.Instantiation().addVarsFromModel(bn, ["B", "A"]) m1 = gum.Instantiation().add(bn.variable("A")).add(bn.variable("B")) m2 = gum.Instantiation().add(bn.variable("B")).add(bn.variable("A")) self.assertEqual(i, m1) self.assertEqual(i, m2) m1.inc() self.assertNotEqual(i, m1)
def seriesToInstantiation(mn, df): d = df.to_dict() I = gum.Instantiation() for i in d.keys(): I.add(mn.variableFromName(i)) I.fromdict(d) return I
def testInsertion(self): mn = gum.MarkovNet() self._fill(mn) with self.assertRaises(gum.InvalidArgument): mn.addFactor(gum.Potential()) # no empty factor with self.assertRaises(gum.InvalidArgument): mn.addFactor({"11", "31"}) # already exist mn1 = gum.MarkovNet() self._fill(mn1) pot = gum.Potential().add(mn1.variable("11")).add(mn1.variable("21")) pot.randomDistribution() mn1.addFactor(pot) self.assertEqual(pot.__str__(), mn1.factor({"11", "21"}).__str__()) mn1 = gum.MarkovNet() self._fill(mn1) pot = gum.Potential().add(mn1.variable("21")).add(mn1.variable("11")) pot.randomDistribution() mn1.addFactor(pot) # should be equal : does not depend of the order of vars in the MarkonNet self.assertEqual(pot.__str__(), mn1.factor({"11", "21"}).__str__()) # but the data should be the same I = gum.Instantiation(pot) factor = mn1.factor({"21", "11"}) I.setFirst() while not I.end(): self.assertAlmostEqual(pot.get(I), factor.get(I), places=7) I.inc()
def draw(p): """ Draw a sample using p :param p: the distribution :return: (v,q) where v is the value and q is the deterministic distribution for v """ q = gum.Potential(p) r = random.random() i = gum.Instantiation(p) val = 0 while not i.end(): if r < 0: q.set(i, 0) else: if r <= p.get(i): val = i.val(0) q.set(i, 1) else: q.set(i, 0) r -= p.get(i) i.inc() if q.sum() != 1: print("ACHTUNG : {} {}".format(p.sum(), p)) print("AND THEN : {}".format(q)) return val,q
def testLogit(self): bn = gum.BayesNet() age = bn.add(gum.RangeVariable("age", "", 35, 67)) taux = bn.add(gum.RangeVariable("taux", "", 115, 171)) angine = bn.add(gum.LabelizedVariable("angine", "")) vc = gum.LabelizedVariable("coeur", "", 0) vc.addLabel("NON").addLabel("OUI") coeur = bn.addLogit(vc, 14.4937) bn.addWeightedArc(age, coeur, -0.1256) bn.addWeightedArc(taux, coeur, -0.0636) bn.addWeightedArc(angine, coeur, 1.779) witness_age = ("50", "49", "46", "49", "62", "35", "67", "65", "47") witness_taux = ("126", "126", "144", "139", "154", "156", "160", "140", "143") witness_angine = ("1", "0", "0", "0", "1", "1", "0", "0", "0") witness_coeur = ("OUI", "OUI", "OUI", "OUI", "OUI", "OUI", "NON", "NON", "NON") witness_proba = (0.8786, 0.5807, 0.3912, 0.3773, 0.2127, 0.8760, 1 - 0.0163, 1 - 0.0710, 1 - 0.3765) inst = gum.Instantiation(bn.cpt(coeur)) for i in range(len(witness_age)): inst.chgVal(bn.variable(age), bn.variable(age)[witness_age[i]]) inst.chgVal(bn.variable(taux), bn.variable(taux)[witness_taux[i]]) inst.chgVal(bn.variable(angine), bn.variable(angine)[witness_angine[i]]) inst.chgVal(bn.variable(coeur), bn.variable(coeur)[witness_coeur[i]]) self.assertAlmostEqual(bn.cpt(coeur).get(inst), witness_proba[i], places=3)
def testEqualities(self): u = gum.LabelizedVariable("u", "u", 4) v = gum.LabelizedVariable("v", "v", 2) w = gum.LabelizedVariable("w", "w", 3) p = gum.Potential().add(u).add(v).add(w) p.random() q = gum.Potential(p) self.assertEqual(p, q) i = gum.Instantiation(q) i.setLast() q[i] = 0 self.assertNotEqual(p, q) q.fillWith(p) self.assertEqual(p, q) q.fillWith(1) self.assertNotEqual(p, q) q.fillWith(p) self.assertEqual(p, q) x = gum.LabelizedVariable("x", "Unknown", 5) q.add(x) self.assertNotEqual(p, q) q = gum.Potential().add(v).add(w) self.assertNotEqual(p, q)
def compactPot(p): res = "" i = gum.Instantiation(p) i.setFirst() while not i.end(): res += "|{:7.3f}".format(100 * p.get(i)) i.inc() return "[" + res[1:] + "]"
def predict_proba(self, X): """ Predicts the probability of classes for each row of input data, with bn's Markov Blanket Parameters ---------- X: str or {array-like, sparse matrix} of shape (n_samples, n_features) or str test data, can be either dataFrame, matrix or name of a csv file Returns ------- array-like of shape (n_samples,) Predicted probability for each classes """ # dictionary of the name of a variable and his column in the data base dictName = self.variableNameIndexDictionary if isinstance(X, pandas.DataFrame): # type(X) == pandas.DataFrame: dictName = DFNames(X) vals = X.to_numpy() elif type(X) == str: vals, _ = self.XYfromCSV(X, target=self.target) dictName = DFNames(vals, vals) vals = vals.to_numpy() else: vals = X if self.fromModel: vals = sklearn.utils.check_array(vals, dtype='str', ensure_2d=False) else: sklearn.utils.check_array(vals, dtype=None, ensure_2d=False) returned_list = [] # label of the target label1 = self.label # list of other labels of the target labels = [self.bn.variable(self.target).label(i) for i in range(self.bn.variable(self.target).domainSize()) if self.bn.variable(self.target).label(i) != self.label] # Instantiation use to apply values of the data base I = self.MarkovBlanket.completeInstantiation() # read through data base's ligns if self.isBinaryClassifier: for x in vals: res = round(_calcul_proba_for_binary_class(x, label1, labels, I, dictName, self.MarkovBlanket, self.target), self.significant_digit) returned_list.append([1 - res, res]) else: local_inst = gum.Instantiation(I) local_inst.erase(self.target) for x in vals: returned_list.append(_calcul_proba_for_nary_class( x, local_inst, dictName, self.MarkovBlanket, self.target).tolist()) return numpy.array(returned_list)
def testRandomPotential(self): u = gum.LabelizedVariable("u", "u", 4) v = gum.LabelizedVariable("v", "v", 2) w = gum.LabelizedVariable("w", "w", 3) p = gum.Potential().add(u).add(v).add(w) I = gum.Instantiation(p) p.random() I.setFirst() while not I.end(): self.assertTrue(p.get(I) <= 1.0) I.inc() p.randomDistribution() I.setFirst() cum = 0 while not I.end(): self.assertTrue(p.get(I) <= 1.0) cum += p.get(I) I.inc() self.assertAlmostEqual(cum, 1.0, 6) p.randomCPT() v = p.variable(0) I.setFirst() while not I.end(): cum = 0.0 I.setFirstVar(v) while not I.end(): self.assertTrue(p.get(I) <= 1.0) cum += p.get(I) I.incVar(v) self.assertAlmostEqual(cum, 1.0, 6) I.unsetEnd() I.incNotVar(v) p.fillWith(1).normalizeAsCPT() I.setFirst() while not I.end(): self.assertAlmostEqual(p.get(I), 0.25, 6) I.inc() alpha = 0.0 while alpha <= 1.0: p.fillWith(1).normalizeAsCPT() p.noising(alpha) min = (1 - alpha) * 0.25 + alpha * 0.0 max = (1 - alpha) * 0.25 + alpha * 1.0 I.setFirst() while not I.end(): self.assertTrue(min <= p.get(I) <= max) I.inc() alpha += 0.1
def testDBNTonda(self): dbn = gum.BayesNet() l = [ dbn.add(gum.LabelizedVariable(name, name, nbr)) for (name, nbr) in [("bf_0", 4), ("bf_t", 4), ("c_0", 5), ( "c_t", 5), ("h_0", 5), ("h_t", 5), ("tf_0", 5), ("tf_t", 5), ("wl_0", 4), ("wl_t", 4)] ] for node in ["c_t", "h_t", "wl_t"]: dbn.addArc(dbn.idFromName("tf_0"), dbn.idFromName(node)) dbn.addArc(dbn.idFromName("bf_0"), dbn.idFromName(node)) dbn.addArc(dbn.idFromName("c_0"), dbn.idFromName("c_t")) dbn.addArc(dbn.idFromName("h_0"), dbn.idFromName("h_t")) dbn.addArc(dbn.idFromName("wl_0"), dbn.idFromName("wl_t")) csvfile = self.agrumSrcDir('DBN_Tonda.csv') l1 = gum.BNLearner(csvfile) l1.setInitialDAG(dbn.dag()) l1.useScoreLog2Likelihood() l1.useSmoothingPrior() bn1 = l1.learnParameters() l2 = gum.BNLearner(csvfile, dbn) l2.setInitialDAG(dbn.dag()) l2.useScoreLog2Likelihood() l2.useSmoothingPrior() bn2 = l2.learnParameters() p1 = bn1.cpt(bn1.idFromName("c_0")) I1 = gum.Instantiation(p1) p2 = bn2.cpt(bn2.idFromName("c_0")) I2 = gum.Instantiation(p2) I1.setFirst() I2.setFirst() while not I1.end(): self.assertEqual(p1.get(I1), p2.get(I2)) I1.inc() I2.inc()
def testWithInstantiation(self): bn = gum.BayesNet() id_list = [] self.fillBN(bn, id_list) list3 = bn.cpt(id_list[3]) list3[:] = [[[1, 0], [0.1, 0.9]], [[0.1, 0.9], [0.01, 0.99]]] i = gum.Instantiation(list3) list3.set(i, 0) i.inc() list3.set(i, 1) self.assertListsAlmostEqual(list3[:], [[[0, 1], [0.1, 0.9]], [[0.1, 0.9], [0.01, 0.99]]]) self.assertListsAlmostEqual(list3[:], bn.cpt(id_list[3])[:])
def testOperatorEqual(self): bn = gum.fastBN("a{chaud|tiede|froid}->b[5]<-c->d->e;c->e") i = bn.completeInstantiation() j = bn.completeInstantiation() self.assertEqual(i, j) while not i.end(): self.assertEqual(i, j) i.inc() self.assertNotEqual(i, j) j.inc() k = gum.Instantiation() self.assertNotEqual(i, k) # not the same size k.inc() self.assertEqual(i, k) # both are in overflow => equals
def compareParams(self, bn1, bn2): # Valeur d'epsilon epsilon = 0 # On calcule la somme des carrés de la difference de toutes les valeurs des BN deux à deux for i in range(len(bn1.names())): inst = gum.Instantiation(bn1.cpt(i)) inst.setFirst() epsilon += pow(bn1.cpt(i).get(inst) - bn2.cpt(i).get(inst), 2) inst.inc() # On divise la somme par le nombre de paramètres epsilon /= len(bn1.names()) return epsilon
def testExtraction(self): a, b, c = [gum.LabelizedVariable(s, s, 3) for s in "abc"] p = gum.Potential().add(a).add(b).fillWith([1, 2, 3, 4, 5, 6, 7, 8, 9]) q = gum.Potential().add(c).fillWith([1, 2, 3]) pot = q * p I = gum.Instantiation() I.add(c) I.chgVal(c, 0) self.assertEqual(pot.extract(I), p) I.chgVal(c, 2) r = gum.Potential().add(a).add(b).fillWith( [3, 6, 9, 12, 15, 18, 21, 24, 27]) self.assertEqual(pot.reorganize(['b', 'c', 'a']).extract(I), r)
def KL(p, q): """ Compute KL(p,k), Kullback-Leibler divergence :param p: gum.Potential :param q: gum.Potential :return: float """ I = gum.Instantiation(p) s = 0 while not I.end(): if p.get(I) > 0: s += p.get(I) * math.log2(p.get(I) / q.get(I)) I.inc() # it may happen that if p==q, s<0 (approximation) return 0 if s <= 0 else s
def draw(p): """ Draw a sample using p :param p: a probability distribution over a variable v :return: (v,q) where v is the value and q is the deterministic distribution for v """ r = random.random() i = gum.Instantiation(p) val = 0 while not i.end(): r -= p.get(i) if r <= 0: val = i.val(0) break i.inc() return val, deterministicPotential(p.variable(0), val)
def implement_constraint(self, bn): bn.cpt('constraint') p_con = bn.cpt('constraint') i_con = gum.Instantiation(p_con) i_con.setFirst() while (not i_con.end()): dict_of_row = i_con.todict(withLabels=True) values = list(dict_of_row.values()) scn, truth_val = dict_of_row['aux'], dict_of_row['constraint'] if scn == "NA": if truth_val == self.truth_values[1]: p_con.set(i_con, 1) else: p_con.set(i_con, 0) else: index_of_label = bn.variable(scn).index( truth_val) # i hate this, but this is the only way to access labels in vars p_con.set(i_con, 1 - bn.cpt(scn)[index_of_label]) i_con.inc()
def testFillWithFunction(self): bn = gum.fastBN( "C[0,1,2,3,4,5,6,7,8]<-A[0,3]->B{0|1|2|3|4|5|6|7|8};A->D[9]") bn.cpt("D").fillWithFunction("3*A+2") I = gum.Instantiation(bn.cpt("D")) while not I.end(): v = 3 * I.val(1) + 2 if v >= I.variable(0).domainSize(): v = I.variable(0).domainSize() - 1 self.assertEqual(bn.cpt("D").get(I), 1 if I.val(0) == v else 0) I.inc() with self.assertRaises(gum.InvalidArgument): bn.cpt("B").fillWithFunction("3*A+2", noise=[2, 1]) with self.assertRaises(gum.InvalidArgument): bn.cpt("B").fillWithFunction("3*A+2")
def create_first_cases(self): new_case_list = [] for scn in self.scenario_nodes: p = self.bn.cpt(scn) i = gum.Instantiation(p) i.setFirst() while (not i.end()): dict_of_row = i.todict(withLabels=True) if dict_of_row[scn] == self.truth_values[0]: # only select the 'true' priors for the first case model line case_name = scn case_scenario = scn case_area = p.get(i) case_width = p.get(i) case_conditional_prior_dict = {scn : case_area} case_evidence_dict = {} new_case = case.Case(case_name, case_scenario, case_area, case_width, case_conditional_prior_dict, case_evidence_dict) new_case_list.append(new_case) i.inc() self.casemodel.cases = new_case_list
def testCopyConstructor(self): pot = gum.Potential() pot.add(self.var['c']) pot.add(self.var['s']) pot.add(self.var['r']) i = gum.Instantiation(pot) val = 1 i.setFirst() while not i.end(): pot.set(i, val) val += 1 i.inc() self.assertEqual(pot.sum(), 36.0) pot2 = gum.Potential(pot) self.assertEqual(pot2.sum(), 36.0) i.setFirst() pot.set(i, 0) # instead of 1 self.assertEqual(pot.sum(), 35.0) self.assertEqual(pot2.sum(), 36.0)
def computePseudoLogLikelihoodData(mn, df): """ Compute the pseudo loglikelihood, on a given markov network, of an instantiation Parameters ---------- mn : pyAgrum.MarkovNet the markov network df : pandas.core.series.Series the instantiation Returns ------- float the pseudo Loglikelihood """ data = df.to_dict() I = gum.Instantiation() for i in data.keys(): I.add(mn.variableFromName(i)) I.fromdict(data) sumPseudoLogLikelihood = 0 factors = factorsName(mn) for variable in data.keys(): originalValue = I[variable] variable = mn.variableFromName(variable) variableFactors = [ factor for factor in factors if variable.name() in factor ] phat = multiplyFactor(variableFactors, I, mn) sommephat = sum([ multiplyFactor(variableFactors, I.chgVal(variable, int(value)), mn) for value in range(variable.domainSize()) ]) I.chgVal(variable, originalValue) sumPseudoLogLikelihood += np.log(phat / sommephat) return sumPseudoLogLikelihood
def implement_aux(self, bn): p_aux = bn.cpt('aux') i_aux = gum.Instantiation(p_aux) i_aux.setFirst() while (not i_aux.end()): dict_of_row = i_aux.todict(withLabels=True) values = list(dict_of_row.values()) num_true = values.count(self.truth_values[0]) if num_true < 1 or num_true > 1: # no scenario is true, aux is NA if dict_of_row['aux'] == "NA": p_aux.set(i_aux, 1) else: p_aux.set(i_aux, 0) else: true_scenario = False for key in dict_of_row.keys(): if dict_of_row[key] == self.truth_values[0]: true_scenario = key if dict_of_row['aux'] == true_scenario: p_aux.set(i_aux, 1) else: p_aux.set(i_aux, 0) i_aux.inc()
#notice appear in supporting documentation or portions #thereof, including modifications, that you make. #THE AUTHOR P.H. WUILLEMIN (@LIP6) DISCLAIMS ALL WARRANTIES #WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED #WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT #SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT #OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER #RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER #IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS #ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE #OR PERFORMANCE OF THIS SOFTWARE! """ How to use Instantiation to iterate in a cpt """ import pyAgrum as gum bn = gum.BayesNet() bn.loadBIF("../resources/bn.bif") p_a = bn.cpt(0) i = gum.Instantiation(p_a) i.setFirst() s = 0.0 while (not i.end()): print i s += p_a.get(i) i.inc() print s
def _reprPotential(pot, digits=None, withColors=True, varnames=None, asString=False): """ return a representation of a gum.Potential as a HTML table. The first dimension is special (horizontal) due to the representation of conditional probability table :param pot: the potential to get :param digits: number of digits to show :param withColors: bgcolor for proba cells or not :param varnames: the aliases for variables name in the table :param asString: display the table or a HTML string :return: the representation """ from fractions import Fraction r0, g0, b0 = gumcols.hex2rgb(gum.config['notebook', 'potential_color_0']) r1, g1, b1 = gumcols.hex2rgb(gum.config['notebook', 'potential_color_1']) if digits is None: digits = gum.config['notebook', 'potential_visible_digits'] if gum.config["notebook", "potential_with_colors"] == "False": withColors = False with_fraction = gum.config['notebook', 'potential_with_fraction'] == "True" if with_fraction: fraction_limit = int(gum.config['notebook', 'potential_fraction_limit']) fraction_round_error = float( gum.config['notebook', 'potential_fraction_round_error']) fraction_with_latex = gum.config[ 'notebook', 'potential_fraction_with_latex'] == "True" def _rgb(r, g, b): return '#%02x%02x%02x' % (r, g, b) def _mkCell(val): s = "<td style='" if withColors and (0 <= val <= 1): r = int(r0 + val * (r1 - r0)) g = int(g0 + val * (g1 - g0)) b = int(b0 + val * (b1 - b0)) tx = gumcols.rgb2brightness(r, g, b) s += "color:" + tx + ";background-color:" + _rgb(r, g, b) + ";" str_val = "" if with_fraction: frac_val = Fraction(val).limit_denominator(fraction_limit) val_app = frac_val.numerator / frac_val.denominator if abs(val_app - val) < fraction_round_error: str_val = "text-align:center;'>" if fraction_with_latex: str_val += "$$" if frac_val.denominator > 1: str_val += f"\\frac{{{frac_val.numerator}}}{{{frac_val.denominator}}}" else: str_val += f"{frac_val.numerator}" str_val += "$$" else: str_val += f"{frac_val}" str_val += "</td>" if str_val == "": str_val = f"text-align:right;'>{val:.{digits}f}</td>" return s + str_val html = list() html.append('<table style="border:1px solid black;">') if pot.empty(): html.append("<tr><th> </th></tr>") html.append("<tr>" + _mkCell(pot.get(gum.Instantiation())) + "</tr>") else: if varnames is not None and len(varnames) != pot.nbrDim(): raise ValueError( f"varnames contains {len(varnames)} value(s) instead of the needed {pot.nbrDim()} value(s)." ) nparents = pot.nbrDim() - 1 var = pot.variable(0) varname = var.name() if varnames == None else varnames[0] # first line if nparents > 0: html.append(f"""<tr><th colspan='{nparents}'></th> <th colspan='{var.domainSize()}' style='border:1px solid black;color:black;background-color:#808080;'><center>{varname}</center> </th></tr>""") else: html.append( f"""<tr style='border:1px solid black;color:black;background-color:#808080'> <th colspan='{var.domainSize()}'><center>{varname}</center></th></tr>""") # second line s = "<tr>" if nparents > 0: # parents order if gum.config["notebook", "potential_parent_values"] == "revmerge": pmin, pmax, pinc = nparents - 1, 0 - 1, -1 else: pmin, pmax, pinc = 0, nparents, 1 if varnames is None: varnames = list(reversed(pot.names)) for par in range(pmin, pmax, pinc): parent = varnames[par] s += f"<th style='border:1px solid black;color:black;background-color:#808080'><center>{parent}</center></th>" for label in var.labels(): s += f"""<th style='border:1px solid black;border-bottom-style: double;color:black;background-color:#BBBBBB'> <center>{label}</center></th>""" s += '</tr>' html.append(s) inst = gum.Instantiation(pot) off = 1 offset = dict() for i in range(1, nparents + 1): offset[i] = off off *= inst.variable(i).domainSize() inst.setFirst() while not inst.end(): s = "<tr>" # parents order if gum.config["notebook", "potential_parent_values"] == "revmerge": pmin, pmax, pinc = 1, nparents + 1, 1 else: pmin, pmax, pinc = nparents, 0, -1 for par in range(pmin, pmax, pinc): label = inst.variable(par).label(inst.val(par)) if par == 1 or gum.config[ "notebook", "potential_parent_values"] == "nomerge": s += f"<th style='border:1px solid black;color:black;background-color:#BBBBBB'><center>{label}</center></th>" else: if sum([inst.val(i) for i in range(1, par)]) == 0: s += f"""<th style='border:1px solid black;color:black;background-color:#BBBBBB;' rowspan = '{offset[par]}'> <center>{label}</center></th>""" for j in range(pot.variable(0).domainSize()): s += _mkCell(pot.get(inst)) inst.inc() s += "</tr>" html.append(s) html.append("</table>") if asString: return "\n".join(html) else: return IPython.display.HTML("".join(html))