Python API¶
Construct circuits on a shared Vtree; combine them with
operators or the named functions below. Transformation methods consume their
circuit inputs. Query methods borrow them. See Using and reusing circuits for the rules
that apply across the API, and What are we counting? for observations, substitution
and projection.
Domains and values¶
- class tididi.Vtree¶
A shared variable decomposition. Reuse one vtree for circuits you will combine.
- static balanced(n)¶
Build a balanced vtree over variables 1 through n. n must be positive.
- static balanced_over(variables)¶
Build a balanced vtree with leaves in the supplied order of distinct positive IDs.
- clear_scratch()¶
Release idle operation scratch without changing any circuit.
- static from_text(text)¶
Parse .vtree text. Reuse the returned object when loading related circuits.
- static join(left, right)¶
Join disjoint vtrees under a new root, leaving both inputs usable.
- static leaf(variable)¶
Build a one-variable vtree.
- static linear(variables)¶
Build a right-linear vtree with leaves in the supplied order.
- to_dot()¶
Return Graphviz DOT describing this vtree.
- to_text()¶
Serialize the shape and variable IDs as .vtree text.
- variables¶
Variable IDs in left-to-right leaf order.
Construction¶
- tididi.literal(vtree, value, *, limits=None)¶
Construct a literal circuit from a signed integer or an immutable Literal value.
- tididi.cube(vtree, literals, *, limits=None)¶
Construct a conjunction of signed integers or Literal values. Omitted variables are free. Each variable may occur once; an empty iterable constructs true.
- tididi.clause(vtree, literals, *, limits=None)¶
Construct a disjunction of literals. An empty iterable constructs false.
- tididi.from_models(vtree, variables, rows, *, limits=None)¶
Construct the set of Boolean rows over variables, leaving other variables free. Every row must contain one bool per variable. Repeated rows count once. Empty rows denote false; one empty row over no variables denotes true.
- tididi.one(vtree)¶
Construct true over every variable of vtree.
- tididi.zero(vtree)¶
Construct false over every variable of vtree.
Boolean composition¶
- tididi.and_(left, right, *, limits=None)¶
Conjoin two circuits, consuming both. Equivalent to left & right, with optional limits. Copy operands first if they must remain usable, including for retry after a resource error.
- tididi.or_(left, right, *, limits=None)¶
Disjoin two circuits, consuming both. Equivalent to left | right, with optional limits.
- tididi.xor(left, right, *, limits=None)¶
Exclusive-or two circuits, consuming both. Also available as left ^ right.
- tididi.ite(condition, then_branch, else_branch, *, limits=None)¶
Build (condition & then_branch) | (~condition & else_branch), consuming all three inputs.
- tididi.or_many(circuits, *, limits=None)¶
Union a nonempty iterable of circuits, consuming every element. Duplicate handles are rejected; pass explicit copies when reusing a circuit.
- tididi.and_exists(left, right, variables, *, limits=None)¶
Conjoin, then existentially quantify variables in one call, consuming both circuits. This computes the same function as (left & right).exists(variables).
Circuits and counters¶
- class tididi.Circuit¶
An owned Boolean circuit. Construct one with literal, cube, clause, from_models, one or zero.
&,|,^,~and transformation methods consume their circuit operands. Queries borrow. copy() explicitly duplicates storage while sharing the vtree. Reusing a consumed object raises ConsumedCircuitError, including through an alias.- condition(literals, *, limits=None)¶
Substitute the given literal values, consuming this circuit. Repeated literals are ignored; opposite signs for one variable produce false. Assigned variables become free in the resulting function’s counting universe. To count assignments consistent with evidence, use counter() instead.
- copy()¶
Duplicate diagram storage, leaving the original usable. The vtree is shared.
- counter()¶
Copy first to retain an independently usable circuit while the counter is open.
- equivalent(other, *, limits=None)¶
Compare Boolean functions without consuming either circuit. Both must share a vtree.
- evaluate(algebra)¶
Evaluate a Python algebra with zero(), leaf(variable, sign), add(a, b), mul(a, b). sign is True, False, or None for a free variable. Values must be immutable; add and mul return new values. Borrows the circuit and propagates callback errors. Python callbacks run attached to the interpreter; use weighted_count for a native exact sum.
- evaluator(weights)¶
Move this circuit into a reusable evidence counter. Call counter.finish() to recover it. Consume this circuit into an exact weighted evaluator. Copy first to retain the circuit. Supply every variable’s (negative, positive) int or Fraction weights.
- exists(variables, *, limits=None)¶
Existentially quantify variables, consuming this circuit. Quantified variables remain free in the vtree; use projected_model_count to count distinct projections.
- static from_bytes(vtree, data)¶
Load serialized circuit bytes onto an existing vtree.
- implied_literals(*, limits=None)¶
Literals true in every model. False implies both signs of every vtree variable.
- implies(other, *, limits=None)¶
Whether every model of this circuit satisfies other. Borrows both circuits.
- is_consumed¶
Whether this wrapper has given up its circuit. This property remains readable afterward.
- is_sat(*, limits=None)¶
Whether at least one assignment satisfies this circuit. Borrows the circuit.
- static load(vtree, path)¶
Read a circuit file onto an existing vtree.
- minimize(*, limits=None)¶
Minimize and return this circuit, consuming the old wrapper. The result is canonical for its vtree; its Boolean function is unchanged.
- model_count(*, limits=None)¶
Count satisfying assignments over all vtree variables. Returns an arbitrary-precision int.
- negate(*, limits=None)¶
Complement this circuit, consuming it. Equivalent to ~circuit, with optional limits.
- node_count()¶
Number of stored circuit nodes, excluding implicit leaf nodes.
- node_sizes()¶
Snapshot of (vtree_node, local_node, pair_count) for every stored internal node. Storage IDs are local to this circuit and may change after transformation.
- pair_count()¶
Number of stored child pairs.
- projected_model_count(variables, *, limits=None)¶
Count distinct assignments to variables that extend to a satisfying assignment.
- rename(mapping, *, limits=None)¶
Simultaneously rename variables using a dict {source: target}, consuming this circuit. Swaps and cycles are simultaneous; several sources may map to the same target. The vtree and its counting universe stay unchanged.
- satisfying_assignment(*, limits=None)¶
One complete satisfying assignment as Literal values, or None if unsatisfiable.
- save(path)¶
Write this circuit to a path, leaving it usable. Save its vtree separately.
- support(*, limits=None)¶
Variable IDs on which the function depends, without consuming the circuit.
- to_bytes()¶
Serialize to bytes. Save the vtree too; related circuits must reload onto one shared vtree.
- to_dot()¶
Return Graphviz DOT for inspecting this circuit.
- update(*, insert=None, remove=None, limits=None)¶
Insert cubes, then remove cubes, returning a minimized circuit and consuming this one. Each cube is an iterable of signed integers or Literal values. Omitted variables are free; an empty cube matches every assignment. Contradictory cubes change nothing. Limits apply to each update and to the final minimization separately.
- vtree¶
The shared vtree. Circuits built on this value can be combined with this circuit.
- weighted_count(weights, *, limits=None)¶
Exact weighted sum as fractions.Fraction. Supply {variable: (negative, positive)} weights, each an int or Fraction, for every vtree variable. Borrows the circuit.
- class tididi.Counter¶
Reuse cached counts while observations change. Created by Circuit.counter(), which consumes it. observe() replaces pins for the named variables; other pins remain. finish() returns the original circuit.
- clear(variable)¶
Remove one observation, leaving that variable free again.
- clear_observations()¶
Remove all observations.
- finish()¶
Discard cached counts and observations, returning the original circuit. Closes this counter.
- model_count(*, limits=None)¶
Count assignments consistent with the observations. Borrows the owned circuit.
- observe(literals)¶
Set observations from signed integers or Literal values without changing the circuit. A later observation for a variable replaces its previous value.
- class tididi.Evaluator¶
Cache exact weighted sums under changing evidence. Circuit.evaluator(weights) consumes the circuit. value() returns the joint weight of the circuit and observations. finish() returns the circuit.
- clear(variable)¶
Clear one observation.
- clear_observations()¶
Clear all observations, retaining cached storage.
- finish()¶
Close this evaluator and return the original circuit without its observations.
- observe(literals)¶
Observe signed integers or Literal values. Invalid input preserves all observations.
- set_weights(weights)¶
Replace every variable’s (negative, positive) weights, retaining observations. Weights are int or Fraction values. Invalid input leaves previous weights in place.
- value(*, limits=None)¶
Return the exact weighted sum under observations, refreshing only affected ancestors. Probability weights give joint probability; no normalization is performed.
Custom evaluation¶
- class tididi.Algebra(*args, **kwargs)¶
Evaluate disjoint alternatives with add and independent groups with mul.
Values must be immutable. Both operations must be associative and commutative; mul distributes over add. zero is the identity for add and absorbing for mul. For each variable, leaf(variable, None) must equal add(leaf(variable, False), leaf(variable, True)): a free variable includes both assignments. Violating these laws can make equivalent circuits evaluate differently. Floating-point arithmetic only approximates the algebraic laws; use exact values when exact results matter.
- zero()¶
The value of an impossible event (the additive identity).
- Return type:
_T
- leaf(variable, sign)¶
Evaluate a positive, negative, or free leaf.
- Parameters:
variable (int)
sign (bool | None)
- Return type:
_T
- add(a, b)¶
Combine disjoint alternatives without mutating either argument.
- Parameters:
a (_T)
b (_T)
- Return type:
_T
- mul(a, b)¶
Combine independent variable groups without mutating either argument.
- Parameters:
a (_T)
b (_T)
- Return type:
_T
Execution and errors¶
- class tididi.Limits(*, memory_bytes=None, output_nodes=None, timeout=None)¶
Optional resource bounds for one operation. Unspecified bounds are unlimited. memory_bytes bounds charged operation storage, not the process’s total memory. timeout is in seconds and is checked at cooperative polling points.
- exception tididi.ConsumedCircuitError¶
A circuit was already consumed. Copy it before a consuming operation to retain it.
- exception tididi.ResourceLimitError¶
An operation exceeded its output-node cap or reached its deadline.