Markov Networks

This page documents classes that are used to define discrete Markov networks. The DiscreteFactor class is used to declare a discrete factor, which is added to a DiscreteMarkovNetwork instance. Further, the ConstrainedDiscreteMarkovNetwork class is used to augment a discrete Markov network with application-specific constraints.

Discrete Factors

The DiscreteFactor class represents a factor defined over one or more discrete nodes. This class has the following public data members:

  • nodes: a list of node identifiers (e.g., strings like "A" or integers).

  • values: a dictionary or a list providing non-negative weights. - dict form: keys are assignments, e.g. {("A_val", "B_val"): weight} or {"A_val": weight}. - list form: a list of weights that are associated with the Cartesian product of node states.

  • default_value: optional fallback value for missing assignments (float, defaults to 0).

Example (unary and pairwise factors)

from conin.markov_network import DiscreteFactor

# Unary factor on A with {0: 1, 1: 1}
fA = DiscreteFactor(["A"], {0: 1, 1: 1})

# Pairwise factor on (A, B)
fAB = DiscreteFactor(["A", "B"], {
    (0, 0): 1,
    (0, 1): 3,
    (1, 0): 1,
    (1, 1): 1,
})

Discrete Markov Networks

A discrete Markov network defined by a set of nodes, optional edges, and a list of factors.

Construction

  • states: define node labels and their possible values, either as - list: node cardinalities (nodes become 0..n-1), or - dict: explicit mapping from node to list of values.

  • edges: optional list of undirected edges [(u, v), ...]. If omitted, edges are derived from factors.

  • factors: list of DiscreteFactor instances. When set, they are normalized against the model’s states.

Example (two-node network, adapted from example6_conin)

from conin.markov_network import DiscreteMarkovNetwork, DiscreteFactor

pgm = DiscreteMarkovNetwork()
pgm.states = {"A": [0, 1], "B": [0, 1]}
pgm.edges = [("A", "B")]

fA = DiscreteFactor(["A"], {0: 1, 1: 1})
fB = DiscreteFactor(["B"], {0: 1, 1: 2})
fAB = DiscreteFactor(["A", "B"], {
    (0, 0): 1,
    (0, 1): 3,
    (1, 0): 1,
    (1, 1): 1,
})

pgm.factors = [fA, fB, fAB]

# Optional: validate
pgm.check_model()

# Optional: build a MAP optimization model
# model = pgm.create_map_query_model()
# Solve with your preferred Pyomo solver (e.g., glpk, highs).

Constrained Discrete Markov Networks

A thin wrapper that augments a base DiscreteMarkovNetwork with user-defined optimization constraints. The constraints are supplied as a functor that takes a Pyomo model and returns the same model with constraints attached.

Example (three nodes with pairwise interactions and a “values must differ” constraint)

import numpy as np
from conin.markov_network import (
    DiscreteMarkovNetwork,
    DiscreteFactor,
    ConstrainedDiscreteMarkovNetwork,
)

# Base PGM (adapted from ABC_conin)
base = DiscreteMarkovNetwork()
base.states = {"A": [0, 1, 2], "B": [0, 1, 2], "C": [0, 1, 2]}
base.edges = [("A", "B"), ("B", "C"), ("A", "C")]

fA = DiscreteFactor(nodes=["A"], values=[1, 1, 2])
fB = DiscreteFactor(nodes=["B"], values=[1, 1, 3])
fC = DiscreteFactor(nodes=["C"], values=[1, 2, 1])
fAB = DiscreteFactor(nodes=["A", "B"], values=np.ones(9))
fBC = DiscreteFactor(nodes=["B", "C"], values=np.ones(9))
fAC = DiscreteFactor(nodes=["A", "C"], values=np.ones(9))
base.factors = [fA, fB, fC, fAB, fBC, fAC]

# Constraint functor applied to the Pyomo model
def constraint_fn(model):
    @model.Constraint([0, 1, 2])
    def all_different(m, s):
        # At most one variable can take the value s
        return m.X["A", s] + m.X["B", s] + m.X["C", s] <= 1
    return model

constrained = ConstrainedDiscreteMarkovNetwork(base, constraints=constraint_fn)

# Build the constrained MAP model
# model = constrained.create_map_query_model()
# Solve with your preferred Pyomo solver.

Notes and Behaviors

  • Factors must have non-negative weights; check_model asserts this.

  • When factor values are provided as lists, they are normalized using the model’s state order to a dictionary keyed by assignments.

  • If edges are not set explicitly, they are inferred from factor scopes.

  • create_map_query_model relies on Pyomo; ensure a compatible solver is installed to optimize the model.