def test_dnf_form() -> None: assert venn_from_str('1 & 2', int).to_dnf_set().is_equivalent_to( venn_from_str('1 & 2', int)) assert venn_from_str('1 | 2', int).to_dnf_set().is_equivalent_to( venn_from_str('1 | 2', int)) assert UniversalSet().to_dnf_set().is_equivalent_to(UniversalSet()) assert EmptySet().to_dnf_set().is_equivalent_to(EmptySet())
def test_superset_subset_for_unary_sets() -> None: # UniversalSet == UniversalSet assert UniversalSet().is_superset_of(UniversalSet()) assert UniversalSet().is_subset_of(UniversalSet()) # UniversalSet contains all other sets assert UniversalSet().is_superset_of(EmptySet()) assert UniversalSet().is_superset_of(ValueSet(1)) # EmptySet is contained in all sets assert EmptySet().is_subset_of(EmptySet()) assert EmptySet().is_superset_of(EmptySet()) assert EmptySet().is_subset_of(ValueSet(2)) # PropertySets <-> PropertySets assert ValueSet(2).is_superset_of(ValueSet(2)) assert ValueSet(2).is_subset_of(ValueSet(2)) assert not ValueSet(2).is_subset_of(ValueSet(3)) assert not ValueSet(2).is_superset_of(ValueSet(3)) # PropertySet <-> UniversalSet assert ValueSet(1).is_subset_of(UniversalSet()) assert not UniversalSet().is_subset_of(ValueSet(1)) assert UniversalSet().is_superset_of(ValueSet(1)) assert not ValueSet(1).is_superset_of(UniversalSet()) # PropertySet <-> EmptySet assert ValueSet(2).is_superset_of(EmptySet()) assert not EmptySet().is_superset_of(ValueSet(2)) assert EmptySet().is_subset_of(ValueSet(1)) assert not ValueSet(1).is_subset_of(EmptySet())
def with_connectivity_constraints(cont_set: VennSet[State]) -> VennSet: complexes = calc_connected_complexes(cont_set.values) complex_constraints = [] for complex in complexes: # pylint: disable=redefined-builtin state_paths = calc_state_paths(complex) constraint = UniversalSet() # type: VennSet[State] for state in complex: assert not state.is_global, 'Global state {} appearing in connectivity constraints.'.format(state) if any(path == [] for path in state_paths[state]): continue state_constraints = [Complement(ValueSet(state))] # type: List[VennSet[State]] for path in state_paths[state]: state_constraints.append(Intersection(*(ValueSet(x) for x in path))) constraint = Intersection(constraint, Union(*state_constraints)) # pylint: disable=redefined-variable-type complex_constraints.append(constraint.to_simplified_set()) if complex_constraints: LOGGER.debug('{} : Complex constraints {}'.format(current_function_name(), ' XOR '.join(str(x) for x in complex_constraints))) return Intersection(cont_set, DisjunctiveUnion(*complex_constraints)) else: return cont_set
def test_is_equivalent_to() -> None: assert UniversalSet().is_equivalent_to(UniversalSet()) assert EmptySet().is_equivalent_to(EmptySet()) assert not UniversalSet().is_equivalent_to(ValueSet(1)) assert not ValueSet(1).is_equivalent_to(UniversalSet()) assert UniversalSet().is_equivalent_to(Union(ValueSet(1), Complement(ValueSet(1))))
def test_intersection_properties(sets: List[Set]) -> None: for x in sets: assert EmptySet().is_equivalent_to(Intersection(x, Complement(x))) assert EmptySet().is_equivalent_to(Intersection(Complement(x), x)) assert EmptySet().is_equivalent_to(Intersection(EmptySet(), x)) assert EmptySet().is_equivalent_to(Intersection(x, EmptySet())) assert x.is_equivalent_to(Intersection(UniversalSet(), x)) assert x.is_equivalent_to(Intersection(x, UniversalSet())) assert x.is_equivalent_to(Intersection(x, x))
def test_nested_list_form() -> None: assert venn_from_str('1', int).to_dnf_nested_list() == [[venn_from_str('1', int)]] x = venn_from_str('1 & ( 2 | 3 )', int) assert [ValueSet(1), ValueSet(2)] in x.to_dnf_nested_list() assert [ValueSet(1), ValueSet(3)] in x.to_dnf_nested_list() assert venn_from_str('1 & 2', int).to_dnf_nested_list() == [[ValueSet(1), ValueSet(2)]] assert venn_from_str('1 | 2', int).to_dnf_nested_list() == [[ValueSet(1)], [ValueSet(2)]] assert UniversalSet().to_dnf_nested_list() == [[UniversalSet()]] assert EmptySet().to_dnf_nested_list() == [[EmptySet()]]
def test_list_form() -> None: assert venn_from_str('1', int).to_dnf_list() == [venn_from_str('1', int)] assert venn_from_str('1 & 2', int).to_dnf_list() == [venn_from_str('1 & 2', int)] assert set(venn_from_str('1 | 2', int).to_dnf_list()) == {ValueSet(1), ValueSet(2)} x = venn_from_str('1 & ( 2 | 3 )', int) assert any(elem.is_equivalent_to(venn_from_str('1 & 2', int)) for elem in x.to_dnf_list()) assert any(elem.is_equivalent_to(venn_from_str('1 & 3', int)) for elem in x.to_dnf_list()) assert UniversalSet().to_dnf_list() == [UniversalSet()] assert EmptySet().to_dnf_list() == [EmptySet()]
def __init__(self, q_contingencies: List[Contingency]) -> None: self.q_contingencies = deepcopy(q_contingencies) combis = [[]] # type: List[List[Contingency]] for contingency in self.q_contingencies: new_combis = [] for combi in combis: new_combis.append(combi + [ Contingency(contingency.reaction, ContingencyType. inhibition, contingency.effector) ]) combi.append( Contingency(contingency.reaction, ContingencyType.requirement, contingency.effector)) combis.extend(new_combis) self.combi_sets = [] # type: List[VennSet[State]] if combis == [[]]: self.combi_sets = [UniversalSet()] else: self.combi_sets = [ Intersection(*(x.to_venn_set() for x in combi)) for combi in combis ] self.current_combi_set = -1
def __init__(self, reaction_parent: Reaction, contingency_variant: Optional[int] = None, interaction_variant: Optional[int] = None, contingency_factor: VennSet['StateTarget'] = None) -> None: self.reaction_parent = reaction_parent # type: Reaction self.produced_targets = [ StateTarget(x) for x in reaction_parent.produced_states ] # type: List[StateTarget] self.consumed_targets = [ StateTarget(x) for x in reaction_parent.consumed_states ] # type: List[StateTarget] self.synthesised_targets = [ StateTarget(x) for x in reaction_parent.synthesised_states ] # type: List[StateTarget] self.degraded_targets = [ StateTarget(x) for x in reaction_parent.degraded_states ] # type: List[StateTarget] self.contingency_variant_index = contingency_variant self.interaction_variant_index = interaction_variant if contingency_factor is None: self.contingency_factor = UniversalSet( ) # type: VennSet[StateTarget] else: self.contingency_factor = contingency_factor # type: VennSet[StateTarget]
def test_nary_sets_constructor() -> None: assert Union() == EmptySet() assert Intersection() == UniversalSet() assert DisjunctiveUnion() == EmptySet() assert Union(venn_from_str('1', int)).is_equivalent_to(venn_from_str('1', int)) assert Intersection(venn_from_str('1', int)).is_equivalent_to(venn_from_str('1', int)) assert DisjunctiveUnion(venn_from_str('1', int)).is_equivalent_to(venn_from_str('1', int))
def sets() -> List[Set]: return [ EmptySet(), ValueSet(1), UniversalSet(), Union(ValueSet(1), ValueSet(2)), Intersection(ValueSet(1), ValueSet(2)), Intersection(ValueSet(1), Complement(ValueSet(2))), Union(Intersection(ValueSet(1), ValueSet(2)), ValueSet(3)), Union(Intersection(ValueSet(1), ValueSet(2)), Intersection(ValueSet(3), ValueSet(4))), Union(Complement(Union(ValueSet(1), Complement(ValueSet(2)))), Intersection(ValueSet(3), ValueSet(4))) ]
def _unsatisfiable_contingencies(self) -> List[Tuple[Reaction, str]]: unsatisfiable = [] for reaction in self.reactions: contingencies = self.s_contingencies_for_reaction(reaction) total_set = UniversalSet() # type: Set[State] for contingency in contingencies: total_set = Intersection(total_set, contingency.to_venn_set()) # pylint: disable=redefined-variable-type solutions = total_set.calc_solutions() if len(solutions) == 0: unsatisfiable.append( (reaction, 'Zero consistent solutions found.')) local_unsatisfiables = [] at_least_one_consistent_soln = False for solution in solutions: trues = [state for state, val in solution.items() if val] if any( state.is_mutually_exclusive_with(other) for state, other in product(trues, trues)): state, other = next( (state, other) for state, other in product(trues, trues) if state.is_mutually_exclusive_with(other)) local_unsatisfiables.append( (reaction, 'State {} mutually exclusive with {}.'.format( str(state), str(other)))) else: at_least_one_consistent_soln = True if not at_least_one_consistent_soln: unsatisfiable += local_unsatisfiables return unsatisfiable
def with_connectivity_constraints(cont_set: VennSet[State], rxncon_system: RxnConSystem) -> VennSet: """Intersect the contingencies with the connectivity constraints.""" if cont_set.is_equivalent_to(UniversalSet()): return cont_set LOGGER.debug( 'with_connectivity_constraints : calculating molecular microstates') components = components_microstate(cont_set, rxncon_system) LOGGER.debug('with_connectivity_constraints : calculating complexes') complexes = bond_complexes(cont_set) constraints = [] for cx in complexes: constraints.append( Intersection(cx.to_venn_set(), *(components[cp] for cp in cx.components))) return Intersection(cont_set, Union(*constraints))
def to_venn_set( self, k_plus_strict: bool = False, k_minus_strict: bool = False, structured: bool = True, state_wrapper: Callable[[State], Any] = lambda x: x) -> VennSet[Any]: def parse_effector(eff: Effector) -> VennSet: if isinstance(eff, StateEffector): if structured: return ValueSet(state_wrapper(eff.expr)) else: return ValueSet(state_wrapper( eff.expr.to_non_structured())) elif isinstance(eff, NotEffector): return Complement(parse_effector(eff.expr)) elif isinstance(eff, OrEffector): return Union(*(parse_effector(x) for x in eff.exprs)) elif isinstance(eff, AndEffector): return Intersection(*(parse_effector(x) for x in eff.exprs)) else: raise AssertionError if k_plus_strict: positive = (ContingencyType.requirement, ContingencyType.positive) else: positive = (ContingencyType.requirement, ) # type: ignore if k_minus_strict: negative = (ContingencyType.inhibition, ContingencyType.negative) else: negative = (ContingencyType.inhibition, ) # type: ignore if self.contingency_type in positive: return parse_effector(self.effector) elif self.contingency_type in negative: return Complement(parse_effector(self.effector)) else: return UniversalSet()
def to_venn_set(self, k_plus_strict: bool=False, k_minus_strict: bool=False, structured: bool=True, state_wrapper: Callable[[State], Any]=lambda x: x) -> VennSet[Any]: """Returns a Venntastic Set object corresponding to the Contingency: requirements are put in a ValueSet, inhibitions in a ValueSet within a Complement. If `k_plus_strict` / `k_minus_strict`, then positive and negative Contingencies are translated into strict requirements resp. strict inhibitions. If `structured` is False, the structure information is discarded. Optionally all States can be wrapped in some other class by providing a `state_wrapper`.""" def parse_effector(eff: Effector) -> VennSet: if isinstance(eff, StateEffector): if structured: return ValueSet(state_wrapper(eff.expr)) else: return ValueSet(state_wrapper(eff.expr.to_non_structured())) elif isinstance(eff, NotEffector): return Complement(parse_effector(eff.expr)) elif isinstance(eff, OrEffector): return Union(*(parse_effector(x) for x in eff.exprs)) elif isinstance(eff, AndEffector): return Intersection(*(parse_effector(x) for x in eff.exprs)) else: raise AssertionError('Unknown Effector {}'.format(str(eff))) if k_plus_strict: positive = (ContingencyType.requirement, ContingencyType.positive) else: positive = (ContingencyType.requirement,) # type: ignore if k_minus_strict: negative = (ContingencyType.inhibition, ContingencyType.negative) else: negative = (ContingencyType.inhibition,) # type: ignore if self.contingency_type in positive: return parse_effector(self.effector) elif self.contingency_type in negative: return Complement(parse_effector(self.effector)) else: return UniversalSet()
def _unsatisfiable_contingencies(self) -> List[Tuple[Reaction, str]]: """Determines the contingencies that are not satisfiable, returns a list of (Reaction, str) where the str contains the human-readable reason for the contingency not being satisfiable.""" unsatisfiable = [] for reaction in self.reactions: contingencies = self.s_contingencies_for_reaction(reaction) # Make sure the contingency does not contain the states produced / consumed by the reaction. states = (state for contingency in contingencies for state in contingency.effector.states) for state in states: # We need to be talking about the states mentioning the reactants. if not all(spec.struct_index in (0, 1) for spec in state.specs): continue if any(count > 1 for count in Counter(reaction.components_rhs).values()): continue # States appear non-structured in the '.produced_states' etc. properties. state = state.to_non_structured() if state in reaction.produced_states and state not in reaction.synthesised_states: unsatisfiable.append( (reaction, 'Produced state {} appears in contingencies'.format( str(state)))) if state in reaction.consumed_states and state not in reaction.degraded_states: unsatisfiable.append( (reaction, 'Consumed state {} appears in contingencies'.format( str(state)))) # Make sure at least one solution is there (this might still contain mutually exclusive states) total_set = UniversalSet() # type: Set[State] for contingency in contingencies: total_set = Intersection(total_set, contingency.to_venn_set()) # pylint: disable=redefined-variable-type solutions = total_set.calc_solutions() if len(solutions) == 0: unsatisfiable.append( (reaction, 'Zero consistent solutions found.')) # Make sure that at least one solution doesn't contain mutually exclusive states. local_unsatisfiables = [] at_least_one_consistent_soln = False for solution in solutions: trues = [state for state, val in solution.items() if val] if any( state.is_mutually_exclusive_with(other) for state, other in product(trues, trues)): state, other = next( (state, other) for state, other in product(trues, trues) if state.is_mutually_exclusive_with(other)) local_unsatisfiables.append( (reaction, 'State {} mutually exclusive with {}.'.format( str(state), str(other)))) else: at_least_one_consistent_soln = True if not at_least_one_consistent_soln: unsatisfiable += local_unsatisfiables return unsatisfiable