This commit is contained in:
Brandon Rozek 2025-11-25 14:28:04 -05:00 committed by GitHub
commit fa30f8303c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

101
vsp.py
View file

@ -3,7 +3,7 @@ Check to see if the model has the variable
sharing property. sharing property.
""" """
from itertools import product from itertools import product
from typing import List, Optional, Set, Tuple from typing import Dict, List, Optional, Set, Tuple
from common import set_to_str from common import set_to_str
from model import ( from model import (
Model, model_closure, ModelFunction, ModelValue Model, model_closure, ModelFunction, ModelValue
@ -43,47 +43,25 @@ def has_vsp(model: Model, impfunction: ModelFunction,
top = model.ordering.top() top = model.ordering.top()
bottom = model.ordering.bottom() bottom = model.ordering.bottom()
# Compute I the set of tuples (x, y) where # Cache of closures
# x -> y does not take a designiated value C: Dict[ModelValue, Set[ModelValue]] = {}
I: List[Tuple[ModelValue, ModelValue]] = []
for (x, y) in product(model.designated_values, model.designated_values):
if impfunction(x, y) not in model.designated_values:
I.append((x, y))
# Find the subalgebras which falsify implication
for xys in I:
xi = xys[0]
for x in model.designated_values:
# Discard ({⊥} A', B) subalgebras # Discard ({⊥} A', B) subalgebras
if bottom is not None and xi == bottom: if bottom is not None and x == bottom:
continue continue
# Discard ({} A', B) subalgebras when negation is defined # Discard ({} A', B) subalgebras when negation is defined
if top is not None and negation_defined and xi == top: if top is not None and negation_defined and x == top:
continue continue
yi = xys[1] candidate_ys = [y for y in model.designated_values if impfunction(x, y) not in model.designated_values]
# Discard (A, {} B') subalgebras if len(candidate_ys) == 0:
if top is not None and yi == top:
continue continue
# Discard (A, {⊥} B') subalgebras when negation is defined carrier_set_left: Set[ModelValue] = model_closure(C.get(x, {x,}), model.logical_operations, bottom)
if bottom is not None and negation_defined and yi == bottom: C[x] = carrier_set_left
continue
# Discard ({a} A', {b} B') subalgebras when a <= b
if model.ordering.is_lt(xi, yi):
continue
# Discard ({a} A', {b} B') subalgebras when b <= a and negation is defined
if negation_defined and model.ordering.is_lt(yi, xi):
continue
# Compute the left closure of the set containing xi under all the operations
carrier_set_left: Set[ModelValue] = model_closure({xi,}, model.logical_operations, bottom)
# Discard ({⊥} A', B) subalgebras # Discard ({⊥} A', B) subalgebras
if bottom is not None and bottom in carrier_set_left: if bottom is not None and bottom in carrier_set_left:
@ -92,32 +70,49 @@ def has_vsp(model: Model, impfunction: ModelFunction,
# Discard ({} A', B) subalgebras when negation is defined # Discard ({} A', B) subalgebras when negation is defined
if top is not None and negation_defined and top in carrier_set_left: if top is not None and negation_defined and top in carrier_set_left:
continue continue
for y in candidate_ys:
# Discard ({a} A', {b} B') subalgebras when a <= b
if model.ordering.is_lt(x, y):
continue
# Compute the closure of all operations # Discard ({a} A', {b} B') subalgebras when b <= a and negation is defined
# with just the ys if negation_defined and model.ordering.is_lt(y, x):
carrier_set_right: Set[ModelValue] = model_closure({yi,}, model.logical_operations, top) continue
# Discard (A, {} B') subalgebras
if top is not None and top in carrier_set_right:
continue
# Discard (A, {⊥} B') subalgebras when negation is defined # Discard (A, {} B') subalgebras
if bottom is not None and negation_defined and bottom in carrier_set_right: if top is not None and y == top:
continue continue
# Discard subalgebras that intersect # Discard (A, {⊥} B') subalgebras when negation is defined
if not carrier_set_left.isdisjoint(carrier_set_right): if bottom is not None and negation_defined and y == bottom:
continue continue
# Check whether for all pairs in the subalgebra, carrier_set_right: Set[ModelValue] = model_closure(C.get(y, {y,}), model.logical_operations, top)
# that implication is falsified. C[y] = carrier_set_right
falsified = True
for (x2, y2) in product(carrier_set_left, carrier_set_right):
if impfunction(x2, y2) in model.designated_values:
falsified = False
break
if falsified: # Discard (A, {} B') subalgebras
return VSP_Result(True, model.name, carrier_set_left, carrier_set_right) if top is not None and top in carrier_set_right:
continue
# Discard (A, {⊥} B') subalgebras when negation is defined
if bottom is not None and negation_defined and bottom in carrier_set_right:
continue
# Discard subalgebras that intersect
if not carrier_set_left.isdisjoint(carrier_set_right):
continue
# Check whether for all pairs in the subalgebra,
# that implication is falsified.
falsified = True
for (x2, y2) in product(carrier_set_left, carrier_set_right):
if impfunction(x2, y2) in model.designated_values:
falsified = False
break
if falsified:
return VSP_Result(True, model.name, carrier_set_left, carrier_set_right)
return VSP_Result(False, model.name) return VSP_Result(False, model.name)