mirror of
https://github.com/Brandon-Rozek/matmod.git
synced 2025-12-19 05:10:25 +00:00
Initial draft of VSP check
This commit is contained in:
parent
39a6bf84fb
commit
e105c4bf5e
4 changed files with 98 additions and 22 deletions
84
model.py
84
model.py
|
|
@ -4,11 +4,13 @@ Defining what it means to be a model
|
|||
from common import set_to_str
|
||||
from logic import (
|
||||
PropositionalVariable, get_propostional_variables, Logic, Term,
|
||||
Operation, Conjunction, Disjunction
|
||||
Operation, Conjunction, Disjunction, Implication
|
||||
)
|
||||
from typing import Set, List, Dict, Tuple, Optional
|
||||
from itertools import product
|
||||
from typing import Set, Dict, Tuple, Optional
|
||||
from functools import lru_cache
|
||||
from itertools import combinations, chain, product
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
__all__ = ['ModelValue', 'ModelFunction', 'Model']
|
||||
|
||||
|
|
@ -33,17 +35,21 @@ class ModelValue:
|
|||
|
||||
|
||||
class ModelFunction:
|
||||
def __init__(self, mapping, operation_name = ""):
|
||||
def __init__(self, arity: int, mapping, operation_name = ""):
|
||||
self.operation_name = operation_name
|
||||
self.arity = arity
|
||||
|
||||
# Correct input to always be a tuple
|
||||
corrected_mapping = dict()
|
||||
for k, v in mapping.items():
|
||||
if isinstance(k, tuple):
|
||||
assert len(k) == arity
|
||||
corrected_mapping[k] = v
|
||||
elif isinstance(k, list):
|
||||
assert len(k) == arity
|
||||
corrected_mapping[tuple(k)] = v
|
||||
else: # Assume it's atomic
|
||||
assert arity == 1
|
||||
corrected_mapping[(k,)] = v
|
||||
|
||||
self.mapping = corrected_mapping
|
||||
|
|
@ -188,9 +194,69 @@ def satisfiable(logic: Logic, model: Model, interpretation: Dict[Operation, Mode
|
|||
if consequent_t not in model.designated_values:
|
||||
return False
|
||||
|
||||
# Make sure ordering constraint is met
|
||||
for premise_t in premise_ts:
|
||||
if consequent_t < premise_t in model.ordering:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def model_closure(initial_set: Set[ModelValue], mfunctions: Set[ModelFunction]):
|
||||
last_set: Set[ModelValue] = set()
|
||||
current_set: Set[ModelValue] = initial_set
|
||||
|
||||
while last_set != current_set:
|
||||
last_set = deepcopy(current_set)
|
||||
|
||||
for mfun in mfunctions:
|
||||
# Get output for every possible input configuration
|
||||
# from last_set
|
||||
for args in product(*(last_set for _ in range(mfun.arity))):
|
||||
current_set.add(mfun(*args))
|
||||
|
||||
return current_set
|
||||
|
||||
def violates_vsp(model: Model, interpretation: Dict[Operation, ModelFunction]) -> bool:
|
||||
"""
|
||||
Tells you whether a model violates the
|
||||
variable sharing property.
|
||||
|
||||
If it returns false, it is still possible that
|
||||
the variable sharing property is violated
|
||||
just that we didn't check for the appopriate
|
||||
subalgebras.
|
||||
"""
|
||||
|
||||
impfunction = interpretation[Implication]
|
||||
|
||||
# Compute I the set of tuples (x, y) where
|
||||
# x -> y does not take a designiated value
|
||||
I: Set[Tuple[ModelValue, ModelValue]] = set()
|
||||
|
||||
for (x, y) in product(model.carrier_set, model.carrier_set):
|
||||
if impfunction(x, y) not in model.designated_values:
|
||||
I.add((x, y))
|
||||
|
||||
# Construct the powerset without the empty set
|
||||
s = list(I)
|
||||
I_power = chain.from_iterable(combinations(s, r) for r in range(1, len(s) + 1))
|
||||
# ((x1, y1)), ((x1, y1), (x2, y2)), ...
|
||||
|
||||
for xys in I_power:
|
||||
# Compute the closure of all operations
|
||||
# with just the xs
|
||||
xs = {xy[0] for xy in xys}
|
||||
carrier_set_left: Set[ModelValue] = model_closure(xs, model.logical_operations)
|
||||
|
||||
# Compute the closure of all operations
|
||||
# with just the ys
|
||||
ys = {xy[1] for xy in xys}
|
||||
carrier_set_right: Set[ModelValue] = model_closure(ys, model.logical_operations)
|
||||
|
||||
# If the carrier set intersects, then we violate VSP
|
||||
if len(carrier_set_left & carrier_set_right) > 0:
|
||||
print("FAIL: Carrier sets intersect")
|
||||
return True
|
||||
|
||||
for (x2, y2) in product(carrier_set_left, carrier_set_right):
|
||||
if impfunction(x2, y2) in model.designated_values:
|
||||
print(f"({x2}, {y2}) take on a designated value")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue