mirror of
https://github.com/Brandon-Rozek/matmod.git
synced 2026-01-18 07:10:23 +00:00
Added logic_has_vsp which uses the SMTLogicEncoder
This commit is contained in:
parent
95e482a265
commit
4150ac2a7a
2 changed files with 76 additions and 9 deletions
10
smt.py
10
smt.py
|
|
@ -221,12 +221,6 @@ class SMTLogicEncoder:
|
||||||
def create_exclusion_constraint(self, model: Model) -> z3.BoolRef:
|
def create_exclusion_constraint(self, model: Model) -> z3.BoolRef:
|
||||||
"""
|
"""
|
||||||
Create a constraint that excludes the given model from future solutions.
|
Create a constraint that excludes the given model from future solutions.
|
||||||
|
|
||||||
Args:
|
|
||||||
model: The model to exclude
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
An SMT constraint ensuring at least one aspect differs
|
|
||||||
"""
|
"""
|
||||||
constraints = []
|
constraints = []
|
||||||
|
|
||||||
|
|
@ -245,7 +239,7 @@ class SMTLogicEncoder:
|
||||||
smt_inputs = tuple(model_value_to_smt[inp] for inp in inputs)
|
smt_inputs = tuple(model_value_to_smt[inp] for inp in inputs)
|
||||||
smt_output = model_value_to_smt[output]
|
smt_output = model_value_to_smt[output]
|
||||||
|
|
||||||
# This input->output mapping should differ
|
# For future models the input->output mapping may differ
|
||||||
constraints.append(smt_func(*smt_inputs) != smt_output)
|
constraints.append(smt_func(*smt_inputs) != smt_output)
|
||||||
|
|
||||||
# Exclude designated value set
|
# Exclude designated value set
|
||||||
|
|
@ -253,7 +247,7 @@ class SMTLogicEncoder:
|
||||||
model_val = ModelValue(str(smt_elem))
|
model_val = ModelValue(str(smt_elem))
|
||||||
is_designated_in_model = model_val in model.designated_values
|
is_designated_in_model = model_val in model.designated_values
|
||||||
|
|
||||||
# Designation should differ
|
# Designation may differ
|
||||||
if is_designated_in_model:
|
if is_designated_in_model:
|
||||||
constraints.append(self.is_designated(smt_elem) == False)
|
constraints.append(self.is_designated(smt_elem) == False)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
75
vsp.py
75
vsp.py
|
|
@ -5,6 +5,7 @@ sharing property.
|
||||||
from itertools import product
|
from itertools import product
|
||||||
from typing import List, Optional, Set, Tuple
|
from typing import List, Optional, Set, Tuple
|
||||||
from common import set_to_str
|
from common import set_to_str
|
||||||
|
from logic import Logic, Implication
|
||||||
from model import (
|
from model import (
|
||||||
Model, model_closure, ModelFunction, ModelValue
|
Model, model_closure, ModelFunction, ModelValue
|
||||||
)
|
)
|
||||||
|
|
@ -12,7 +13,7 @@ from model import (
|
||||||
SMT_LOADED = True
|
SMT_LOADED = True
|
||||||
try:
|
try:
|
||||||
from z3 import And, Or, Implies, sat
|
from z3 import And, Or, Implies, sat
|
||||||
from smt import SMTModelEncoder
|
from smt import SMTModelEncoder, SMTLogicEncoder
|
||||||
except ImportError:
|
except ImportError:
|
||||||
SMT_LOADED = False
|
SMT_LOADED = False
|
||||||
|
|
||||||
|
|
@ -194,3 +195,75 @@ def has_vsp(model: Model, impfunction: ModelFunction,
|
||||||
return has_vsp_magical(model, impfunction, negation_defined)
|
return has_vsp_magical(model, impfunction, negation_defined)
|
||||||
|
|
||||||
return has_vsp_smt(model)
|
return has_vsp_smt(model)
|
||||||
|
|
||||||
|
|
||||||
|
def logic_has_vsp(logic: Logic, size: int) -> Optional[Tuple[Model, VSP_Result]]:
|
||||||
|
"""
|
||||||
|
Checks whether a given logic satisfies
|
||||||
|
the variable sharing property by looking
|
||||||
|
for a many-valued matrix of a specific size.
|
||||||
|
|
||||||
|
If the logic does witness the VSP, then
|
||||||
|
this function will return the matrix model
|
||||||
|
and the subalgebras that witness it.
|
||||||
|
|
||||||
|
Otherwise, if no matrix model of that given
|
||||||
|
size can be found, it will return None
|
||||||
|
"""
|
||||||
|
assert size > 0
|
||||||
|
|
||||||
|
encoder = SMTLogicEncoder(logic, size)
|
||||||
|
|
||||||
|
## The following adds constraints which satisfy the VSP
|
||||||
|
|
||||||
|
# Membership Predicates for K1/K2
|
||||||
|
IsInK1 = encoder.create_predicate("IsInK1", 1)
|
||||||
|
IsInK2 = encoder.create_predicate("IsInK2", 1)
|
||||||
|
|
||||||
|
# K1 and K2 are non-empty
|
||||||
|
encoder.solver.add(Or([IsInK1(x) for x in encoder.smt_carrier_set]))
|
||||||
|
encoder.solver.add(Or([IsInK2(x) for x in encoder.smt_carrier_set]))
|
||||||
|
|
||||||
|
# K1/K2 are closed under the operations
|
||||||
|
for op, SmtOp in encoder.operation_function_map.items():
|
||||||
|
for xs in product(encoder.smt_carrier_set, repeat=op.arity):
|
||||||
|
encoder.solver.add(
|
||||||
|
Implies(
|
||||||
|
And([IsInK1(x) for x in xs]),
|
||||||
|
IsInK1(SmtOp(*xs))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
encoder.solver.add(
|
||||||
|
Implies(
|
||||||
|
And([IsInK2(x) for x in xs]),
|
||||||
|
IsInK2(SmtOp(*xs))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# x -> y is non-designated
|
||||||
|
Impfn = encoder.operation_function_map[Implication]
|
||||||
|
for (x, y) in product(encoder.smt_carrier_set, encoder.smt_carrier_set):
|
||||||
|
encoder.solver.add(
|
||||||
|
Implies(
|
||||||
|
And(IsInK1(x), IsInK2(y)),
|
||||||
|
encoder.is_designated(Impfn(x, y)) == False
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
model = encoder.find_model()
|
||||||
|
|
||||||
|
# We failed to find a VSP witness
|
||||||
|
if model is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Otherwise, a matrix model and correspoding
|
||||||
|
# subalgebras exist.
|
||||||
|
|
||||||
|
smt_model = encoder.solver.model()
|
||||||
|
K1_smt = [x for x in encoder.smt_carrier_set if smt_model.evaluate(IsInK1(x))]
|
||||||
|
K1 = {ModelValue(str(x)) for x in K1_smt}
|
||||||
|
|
||||||
|
K2_smt = [x for x in encoder.smt_carrier_set if smt_model.evaluate(IsInK2(x))]
|
||||||
|
K2 = {ModelValue(str(x)) for x in K2_smt}
|
||||||
|
|
||||||
|
return model, VSP_Result(True, model.name, K1, K2)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue