def _tree_builder(self, to_expand): """ Recursive helper method to build a SymbolTree. Fills in the children of to_expand by all possible model substitutions. Args: to_expand: (TreeElement) element that will be expanded Returns: None """ # Get set of symbols that no longer need to be replaced and # symbols that are candidates for replacement. replaced_symbols = set() # set of all symbols already replaced. # equal to all parents' minus expand's symbols. parent = to_expand.parent while parent is not None: replaced_symbols.update(parent.inputs) parent = parent.parent replaced_symbols -= to_expand.inputs candidate_symbols = to_expand.inputs - replaced_symbols # Attempt to replace candidate_symbols # Replace them with inputs to models that output the candidate_symbols. # Store replacements. outputs = [] prev = defaultdict(list) # TODO: this also might be too complicated, marking for refactor for symbol in candidate_symbols: c_models = self._output_to_model[symbol] for model in c_models: for input_set, output_set in zip(model.input_sets, model.output_sets): can_continue = True for input_symbol in input_set: if input_symbol in replaced_symbols: can_continue = False break if not can_continue: continue input_set = input_set | model.constraint_properties new_types = (to_expand.inputs - output_set) new_types.update(input_set) new_types = {self._symbol_types[x] for x in new_types} if new_types in prev[model]: continue prev[model].append(new_types) new_element = TreeElement(model, new_types, to_expand, None) self._tree_builder(new_element) outputs.append(new_element) # Add outputs to children and fill in their elements. to_expand.children = outputs
def required_inputs_for_property(self, property): """ Determines all potential paths leading to a given symbol object. Answers the question: What sets of properties are required to calculate this given property? Paths are represented as a series of models and required input Symbol objects. Paths can be searched to determine specifically how to get from one property to another. Warning: Method indicates sets of Symbol objects required to calculate the property. It does not indicate how many of each Symbol is required. It does not guarantee that supplying Quantities of these types will result in a new Symbol output as conditions / assumptions may not be met. Returns: propnet.core.utils.SymbolTree """ head = TreeElement(None, {property}, None, None) self._tree_builder(head) return SymbolTree(head)