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 _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