def mol_defs_from_rxncon(rxncon_sys: RxnConSystem) -> List[MolDef]: mol_defs = {} for spec in rxncon_sys.components(): LOGGER.debug('{} : Creating MolDefBuilder for {}'.format(current_function_name(), str(spec))) builder = MolDefBuilder(spec) for state in rxncon_sys.states_for_component(spec): LOGGER.debug('{} : Applying State {} of type {}'.format(current_function_name(), str(state), type(state))) for func in STATE_TO_MOL_DEF_BUILDER_FN[type(state)]: func(state, builder) mol_defs[spec] = builder.build() return list(mol_defs.values())
def components_microstate( cont_set: VennSet[State], rxncon_system: RxnConSystem) -> Dict[Spec, VennSet[State]]: """Returns, for each component, the VennSet expression for the modification states.""" bond_filter = make_bond_filter(cont_set) comp_to_states = group_states(cont_set, lambda s: not bond_filter(s)) constraints = dict() # type: Dict[Spec, VennSet[State]] for comp, states in comp_to_states.items(): def state_to_locus(state: State) -> Locus: return state.specs[0].locus complement_states = set() for state in states: complement_states |= set( rxncon_system.complement_states_for_component(comp, state)) states = set(states) | complement_states comp_constraint = Intersection() # type: VennSet[State] for _, locus_states in groupby(sorted(states, key=state_to_locus), state_to_locus): comp_constraint = Intersection( comp_constraint, DisjunctiveUnion(*(ValueSet(s) for s in locus_states))) constraints[comp] = comp_constraint return constraints
def calc_observables(rxncon_sys: RxnConSystem) -> List[Observable]: def observable_complex(states: List[State]) -> Complex: builder = ComplexExprBuilder() assert all(x.is_structured for x in states) for state in states: for func in STATE_TO_COMPLEX_BUILDER_FN[type(state)]: func(state, builder) complexes = builder.build(only_reactants=False) assert len(complexes) == 1 return complexes[0] observables = [] output_rxns = [rxn for rxn in rxncon_sys.reactions if isinstance(rxn, OutputReaction)] for rxn in output_rxns: LOGGER.debug('{} : calculating observable {}'.format(current_function_name(), str(rxn))) solns = Intersection(*(x.to_venn_set() for x in rxncon_sys.contingencies_for_reaction(rxn))).calc_solutions() positive_solns = [] # type: List[List[State]] for soln in solns: positive_solns += calc_positive_solutions(rxncon_sys, soln) for index, positive_soln in enumerate(positive_solns): LOGGER.debug('{} : solution {} : {}'.format(current_function_name(), index, positive_soln)) observables.append(Observable('{}{}'.format(rxn.name, index), observable_complex(positive_soln))) return observables
def _construct_rxncon_system(self) -> None: self._rxncon_system = RxnConSystem(self._reactions, self._contingencies)
def rule_based_model_from_rxncon(rxncon_sys: RxnConSystem) -> RuleBasedModel: # pylint: disable=too-many-locals """Returns a RBM given a rxncon system.""" def mol_defs_from_rxncon(rxncon_sys: RxnConSystem) -> List[MolDef]: mol_defs = {} for spec in rxncon_sys.components(): LOGGER.debug( 'mol_defs_from_rxncon : Creating MolDefBuilder for {}'.format( str(spec))) builder = MolDefBuilder(spec) for state in rxncon_sys.states_for_component(spec): LOGGER.debug( 'mol_defs_from_rxncon : Applying State {} of type {}'. format(str(state), type(state))) for func in STATE_TO_MOL_DEF_BUILDER_FN[type( state)]: # type: ignore func(state, builder) mol_defs[spec] = builder.build() return list(mol_defs.values()) def remove_global_states( solutions: List[Dict[State, bool]]) -> List[Dict[State, bool]]: filtered_solutions = [] # type: List[Dict[State, bool]] for soln in solutions: cleaned_solution = {} for state, val in soln.items(): if state.is_global: LOGGER.warning( 'remove_global_states : REMOVING INPUT STATE {} from contingencies.' .format(state)) else: cleaned_solution[state] = val if cleaned_solution not in filtered_solutions: filtered_solutions.append(cleaned_solution) return filtered_solutions def is_satisfiable(states: Iterable[State]) -> bool: for pair in combinations(states, 2): if pair[0].is_mutually_exclusive_with(pair[1]): return False return True def calc_positive_solutions( rxncon_sys: RxnConSystem, solution: Dict[State, bool]) -> List[List[State]]: def complementary_state_combos(state: State) -> List[List[State]]: combos = product(*(rxncon_sys.complement_states_for_component( spec.to_component_spec(), state) for spec in state.specs)) return [list(combo) for combo in combos if is_satisfiable(combo)] def structure_states(states: List[State]) -> List[State]: cur_index = max(spec.struct_index for state in states for spec in state.specs if spec.is_structured) assert cur_index is not None spec_to_index = {} # type: Dict[Spec, int] struct_states = [] # type: List[State] for state in states: if state.is_structured: struct_states.append(state) continue for spec in state.specs: if spec.is_structured: continue try: state = state.to_structured_from_spec( spec.with_struct_index( spec_to_index[spec.to_component_spec()])) except KeyError: cur_index += 1 state = state.to_structured_from_spec( spec.with_struct_index(cur_index)) spec_to_index[spec.to_component_spec()] = cur_index struct_states.append(state) return struct_states ordered_solution = OrderedDict( sorted(solution.items(), key=lambda x: x[0])) trues = [state for state, val in ordered_solution.items() if val] falses = [ state for state, val in ordered_solution.items() if not val and not any( state.is_mutually_exclusive_with(x) for x in trues) ] if not falses: return [trues] if is_satisfiable(trues) else [] positivized_falses = [ list(chain(*x)) for x in product(*(complementary_state_combos(state) for state in falses)) ] solutions = [] for positivized_false in positivized_falses: possible_solution = [] # type: List[State] for soln_state in structure_states(trues + positivized_false): if soln_state not in possible_solution: possible_solution.append(soln_state) if is_satisfiable(possible_solution): solutions.append(possible_solution) return solutions def calc_rule(reaction: Reaction, cont_soln: List[State], quant_cont: VennSet[State]) -> Rule: def calc_complexes(terms: List[ReactionTerm], states: List[State]) -> List[Complex]: if not all(x.is_structured for x in states): unstructs = [x for x in states if not x.is_structured] raise AssertionError( 'Error in building rule for Reaction {}, States {} appear unstructured' .format(str(reaction), ', '.join(str(x) for x in unstructs))) if not is_satisfiable(cont_soln): raise AssertionError( 'Cannot satisfy contingencies {} simultaneously'.format( ' & '.join(str(s) for s in cont_soln))) states = copy(states) builder = ComplexExprBuilder(reaction=reaction) struct_index = 0 for term in terms: struct_states = deepcopy(term.states) for spec in term.specs: struct_spec = copy(spec) struct_spec.struct_index = struct_index builder.add_mol(struct_spec, is_reactant=True) struct_states = [ state.to_structured_from_spec(struct_spec) for state in struct_states ] struct_index += 1 states += struct_states assert all(x.is_structured for x in states) for state in states: for func in STATE_TO_COMPLEX_BUILDER_FN[type( state)]: # type: ignore func(state, builder) return builder.build() lhs = calc_complexes(reaction.terms_lhs, cont_soln) rhs = calc_complexes(reaction.terms_rhs, cont_soln) rate = Parameter('k_{}{}'.format( rxncon_sys.reaction_number(reaction) + 1, quant_cont.rate_constant_desc), '1.0', description=str(reaction)) return Rule(lhs, rhs, rate, parent_reaction=reaction, quant_cont=quant_cont) def calc_initial_conditions( mol_defs: List[MolDef]) -> List[InitialCondition]: return \ [InitialCondition(mol_def.create_neutral_complex(), Parameter('Num{}'.format(mol_def.name), str(INITIAL_MOLECULE_COUNT))) for mol_def in mol_defs] def calc_observables(rxncon_sys: RxnConSystem) -> List[Observable]: def observable_complex(states: List[State]) -> Complex: builder = ComplexExprBuilder() assert all(x.is_structured for x in states), 'Unstructured states appearing in observable ' \ '{}'.format(states) for state in states: for func in STATE_TO_COMPLEX_BUILDER_FN[type( state)]: # type: ignore func(state, builder) complexes = builder.build(only_reactants=False) assert len( complexes ) == 1, 'Multiple complexes appearing in observable {}'.format( states) return complexes[0] observables = [] output_rxns = [ rxn for rxn in rxncon_sys.reactions if isinstance(rxn, OutputReaction) ] for rxn in output_rxns: LOGGER.debug('calc_observables : calculating observable {}'.format( str(rxn))) solns = Intersection( *(x.to_venn_set() for x in rxncon_sys.contingencies_for_reaction(rxn) )).calc_solutions() positive_solns = [] # type: List[List[State]] for soln in solns: positive_solns += calc_positive_solutions(rxncon_sys, soln) for index, positive_soln in enumerate(positive_solns): LOGGER.debug('calc_observables : solution {} : {}'.format( index, positive_soln)) observables.append( Observable('{}{}'.format(rxn.name, index), observable_complex(positive_soln))) return observables mol_defs = mol_defs_from_rxncon(rxncon_sys) LOGGER.debug('rule_based_model_from_rxncon : Generated MolDefs: {}'.format( ', '.join(str(mol_def) for mol_def in mol_defs))) rules = [] # type: List[Rule] for reaction in (x for x in rxncon_sys.reactions if not isinstance(x, OutputReaction)): LOGGER.debug( 'rule_based_model_from_rxncon : Generating rules for reaction {}'. format(str(reaction))) strict_cont_set = Intersection( *(x.to_venn_set() for x in rxncon_sys.s_contingencies_for_reaction(reaction) )) # type: VennSet[State] quant_contingencies = QuantContingencyConfigs( rxncon_sys.q_contingencies_for_reaction(reaction)) LOGGER.debug( 'rule_based_model_from_rxncon : Strict contingencies {}'.format( str(strict_cont_set))) found_solution = False for quant_contingency_set in quant_contingencies: LOGGER.debug( 'rule_based_model_from_rxncon : quantitative contingency config: {}' .format(str(quant_contingency_set))) cont_set = Intersection( strict_cont_set, quant_contingency_set) # type: VennSet[State] LOGGER.debug( 'rule_based_model_from_rxncon : adding constraints...') cont_set = with_connectivity_constraints(cont_set, rxncon_sys) LOGGER.debug( 'rule_based_model_from_rxncon {} : calculating solutions...'. format(datetime.now())) solutions = cont_set.calc_solutions() LOGGER.debug( 'rule_based_model_from_rxncon {} : found {} non-positivized solutions...' .format(datetime.now(), len(solutions))) solutions = remove_global_states(solutions) LOGGER.debug( 'rule_based_model_from_rxncon : contingency solutions {}'. format(str(solutions))) positive_solutions = [] # type: List[List[State]] for solution in solutions: positive_solutions += calc_positive_solutions( rxncon_sys, solution) for positive_solution in positive_solutions: found_solution = True LOGGER.debug( 'rule_based_model_from_rxncon : positivized contingency solution {}' .format(' & '.join(str(x) for x in positive_solution))) rule = calc_rule(reaction, positive_solution, quant_contingency_set) if not any( rule.is_equivalent_to(existing) for existing in rules): rules.append(rule) if not found_solution: LOGGER.error( 'rule_based_model_from_rxncon : could not find positive solutions for rxn {}' .format(str(reaction))) return RuleBasedModel(mol_defs, calc_initial_conditions(mol_defs), [], calc_observables(rxncon_sys), rules)
def complementary_state_targets(self, rxnconsys: RxnConSystem, component: Spec) -> List['StateTarget']: others = rxnconsys.complement_states_for_component( component, self.state_parent) return [StateTarget(x) for x in others]