Description
If this request is about a new feature, please describe what you would like to see implemented.
How about adding built-in support for pseudo-boolean constraints in Satisfiability.jl,
similar to the PbEq, PbLe, and PbGe functionality available in the Z3 theorem prover. I would be pleased to work on this, should you approve the feature request.
These constraints allow users to efficiently express conditions such as:
-
PbEq: Exactly
$K$ out of$N$ are true —$\text{PbEq}(((x_1, 1), (x_2, 1), \ldots, (x_N, 1)), K)$ —$x_1 + x_2 + \cdots + x_N = K$ -
PbLe: At most
$K$ out of$N$ are true —$\text{PbLe}(((x_1, 1), (x_2, 1), \ldots, (x_N, 1)), K)$ —$x_1 + x_2 + \cdots + x_N \leq K$ -
PbGe: At least
$K$ out of$N$ are true —$\text{PbGe}(((x_1, 1), (x_2, 1), \ldots, (x_N, 1)), K)$ —$x_1 + x_2 + \cdots + x_N \geq K$
Proposed syntax example
To express these constraints in Julia, maybe we could use the following syntax. Please let me know your feedback, is this the reasonable API:
-
PbEq (exactly K true):
assert!(solver, PbEq([(x[i], 1) for i in 1:N], K))
-
PbLe (at most K true):
assert!(solver, PbLe([(x[i], 1) for i in 1:N], K))
-
PbGe (at least K true):
assert!(solver, PbGe([(x[i], 1) for i in 1:N], K))
If this request is about an existing feature, what is the current behavior and what is the use case for changing the behavior?
Currently,Satisfiability.jl
does not provide a dedicated API for pseudo-boolean constraints . Users must encode pseudo-boolean constraints manually by introducing auxiliary variables and additional constraints, which can be tedious and less efficient. According to this discussion, to express a 1-out-of-N
constraint, one can manually assert that at least one variable is true
(or(x₁, ..., xₙ))
and that at most one variable is true
(not(and(xᵢ, xⱼ))
for all pairs of distinct indices i
and j
). While there are various ways to manually encode such constraints (including for K-out-of-N
), having built-in support in the solver maybe efficient than encoding them manually. Built-in support would therefore simplify problem modeling particularly for large-scale problems.
Additional context
Inspiration: https://stackoverflow.com/questions/43081929/k-out-of-n-constraint-in-z3py
SMT-LIB syntax: Is there a way to access PbEq/PbLe/PgGe via smt-lib?
Ways to manually express the 1-out-of-N
and K-out-of-N
constraints Encoding 1-out-of-n constraint for SAT solvers
Some python examples for API cross-reference:
from z3 import *
x1, x2, x3, x4 = Bools('x1 x2 x3 x4')
s = Solver()
s.add(PbEq([(x1, 1), (x2, 1), (x3, 1), (x4, 1)], 2))
print(s.check()) # Output: sat
print(s.model()) # Example: {x1: True, x2: True, x3: False, x4: False}
output
sat
[x3 = False, x2 = True, x1 = False, x4 = True]
import z3
# Function to create and solve the solver with given constraints
def solve_pseudo_boolean_constraint(constraint_type, bvars, K):
s = z3.Solver()
if constraint_type == "PbEq":
# Exactly K variables should be true
s.add(z3.PbEq([(x, 1) for x in bvars], K))
elif constraint_type == "PbLe":
# At most K variables should be true
s.add(z3.PbLe([(x, 1) for x in bvars], K))
elif constraint_type == "PbGe":
# At least K variables should be true
s.add(z3.PbGe([(x, 1) for x in bvars], K))
else:
raise ValueError("Invalid constraint type. Use 'PbEq', 'PbLe', or 'PbGe'.")
# Check satisfiability
result = s.check()
if result == z3.sat:
model = s.model()
print(f"{constraint_type} is SAT")
for var in bvars:
print(f"{var} = {model[var]}")
else:
print(f"{constraint_type} is UNSAT")
# Create 10 boolean variables
bvars = [z3.Bool(f"Var {i}") for i in range(5)]
# Example 1: Exactly 3 of the variables should be true (PbEq)
solve_pseudo_boolean_constraint("PbEq", bvars, 3)
# Example 2: At most 3 of the variables should be true (PbLe)
solve_pseudo_boolean_constraint("PbLe", bvars, 3)
# Example 3: At least 3 of the variables should be true (PbGe)
solve_pseudo_boolean_constraint("PbGe", bvars, 3)
output
PbEq is SAT
Var 0 = True
Var 1 = True
Var 2 = True
Var 3 = False
Var 4 = False
PbLe is SAT
Var 0 = True
Var 1 = True
Var 2 = True
Var 3 = False
Var 4 = False
PbGe is SAT
Var 0 = True
Var 1 = True
Var 2 = True
Var 3 = False
Var 4 = False