def _deep_copy_node(self, node, variable, current_depth, max_depth): if isinstance(node, CircuitTerminal): return node else: if len(node.elements) == 0: raise ValueError( "Decision nodes should have at least one elements.") copied_elements = [] for element in node.elements: copied_elements.append( self._deep_copy_element(element, variable, current_depth + 1, max_depth)) self._largest_index += 1 return OrGate(self._largest_index, node.vtree, copied_elements)
def _copy_and_modify_node_for_split(self, original_node, variable, current_depth, max_depth): if original_node.num_parents == 0: raise ValueError("Some node does not have a parent.") original_node.decrease_num_parents_by_one() if isinstance(original_node, CircuitTerminal): if original_node.var_index == variable: if original_node.var_value == LITERAL_IS_TRUE: copied_node = None elif original_node.var_value == LITERAL_IS_FALSE: original_node = None copied_node = self._terminal_nodes[self._num_variables + variable - 1] else: raise ValueError( "Under the current setting," "we only support terminal nodes that are either positive or negative literals." ) else: copied_node = original_node return original_node, copied_node else: if original_node.num_parents > 0: original_node = self._deep_copy_node(original_node, variable, current_depth, max_depth) copied_elements = [] i = 0 while i < len(original_node.elements): original_element, copied_element = self._copy_and_modify_element_for_split( original_node.elements[i], variable, current_depth + 1, max_depth) if original_element is None: original_node.remove_element(i) else: i += 1 if copied_element is not None: copied_elements.append(copied_element) if len(copied_elements) == 0: copied_node = None else: self._largest_index += 1 copied_node = OrGate(self._largest_index, original_node.vtree, copied_elements) if len(original_node.elements) == 0: original_node = None return original_node, copied_node
def _new_logistic_psdd(self, vtree) -> CircuitNode: left_vtree = vtree.left right_vtree = vtree.right prime_variable = left_vtree.var sub_variable = right_vtree.var if left_vtree.is_leaf(): left_node = self._precreated_terminal_nodes[prime_variable - 1] else: left_node = self._new_logistic_psdd(left_vtree) if right_vtree.is_leaf(): right_node = self._precreated_terminal_nodes[sub_variable - 1] else: right_node = self._new_logistic_psdd(right_vtree) elements = [ AndGate(left_node, right_node, np.random.random_sample(size=(self._num_classes, ))) ] elements[0].splittable_variables = copy.deepcopy(vtree.variables) root = OrGate(self._largest_index, vtree, elements) self._largest_index += 1 return root
def load(self, f): # read the format at the beginning line = f.readline() while line[0] == "c": line = f.readline() # serialize the vtree vtree_nodes = dict() unvisited_vtree_nodes = deque() unvisited_vtree_nodes.append(self._vtree) while len(unvisited_vtree_nodes): node = unvisited_vtree_nodes.popleft() vtree_nodes[node.index] = node if not node.is_leaf(): unvisited_vtree_nodes.append(node.left) unvisited_vtree_nodes.append(node.right) # extract the saved logistic circuit nodes = dict() line = f.readline() while line[0] == "T" or line[0] == "F" or line[0] == "S": line_as_list = line.strip().split(" ") literal_type, var = line_as_list[0], int(line_as_list[3]) index, vtree_index = int(line_as_list[1]), int(line_as_list[2]) parameters = [] for i in range(self._num_classes): parameters.append(float(line_as_list[4 + i])) parameters = np.array(parameters, dtype=np.float64) if literal_type == "T": self._precreated_terminal_nodes[self._num_variables + var - 1].parameter = parameters nodes[index] = ( self._precreated_terminal_nodes[self._num_variables + var - 1], {var}) elif literal_type == "F": self._precreated_terminal_nodes[2 * self._num_variables + var - 1].parameter = parameters nodes[index] = ( self._precreated_terminal_nodes[2 * self._num_variables + var - 1], {-var}) else: self._precreated_terminal_nodes[var - 1].parameter = parameters nodes[index] = (self._precreated_terminal_nodes[var - 1], {-var}) self._largest_index = max(self._largest_index, index) line = f.readline() self._terminal_nodes = [x[0] for x in nodes.values()] root = None while line[0] == "D": line_as_list = line.strip().split(" ") index, vtree_index, num_elements = int(line_as_list[1]), int( line_as_list[2]), int(line_as_list[3]) elements = [] variables = set() for i in range(num_elements): prime_index = int(line_as_list[i * (self._num_classes + 2) + 4].strip("(")) sub_index = int(line_as_list[i * (self._num_classes + 2) + 5]) element_variables = nodes[prime_index][1].union( nodes[sub_index][1]) variables = variables.union(element_variables) splittable_variables = set() for variable in element_variables: if -variable in element_variables: splittable_variables.add(abs(variable)) parameters = [] for j in range(self._num_classes): parameters.append( float(line_as_list[i * (self._num_classes + 2) + 6 + j].strip(")"))) parameters = np.array(parameters, dtype=np.float64) elements.append( AndGate(nodes[prime_index][0], nodes[sub_index][0], parameters)) elements[-1].splittable_variables = splittable_variables nodes[index] = (OrGate(index, vtree_nodes[vtree_index], elements), variables) root = nodes[index][0] self._largest_index = max(self._largest_index, index) line = f.readline() if line[0] != "B": raise ValueError( "The last line in a circuit file must record the bias parameters." ) self._bias = np.array([float(x) for x in line.strip().split(" ")[1:]], dtype=np.float64) gc.collect() return root
def _new_logistic_psdd(self, vtree) -> CircuitNode: left_vtree = vtree.left right_vtree = vtree.right prime_variable = left_vtree.var sub_variable = right_vtree.var elements = list() if left_vtree.is_leaf() and right_vtree.is_leaf(): elements.append( AndGate( self._terminal_nodes[prime_variable - 1], self._terminal_nodes[sub_variable - 1], self.rand_gen.random_sample(size=(self._num_classes, )), )) elements.append( AndGate( self._terminal_nodes[prime_variable - 1], self._terminal_nodes[self._num_variables + sub_variable - 1], self.rand_gen.random_sample(size=(self._num_classes, )), )) elements.append( AndGate( self._terminal_nodes[self._num_variables + prime_variable - 1], self._terminal_nodes[sub_variable - 1], self.rand_gen.random_sample(size=(self._num_classes, )), )) elements.append( AndGate( self._terminal_nodes[self._num_variables + prime_variable - 1], self._terminal_nodes[self._num_variables + sub_variable - 1], self.rand_gen.random_sample(size=(self._num_classes, )), )) elif left_vtree.is_leaf(): elements.append( AndGate( self._terminal_nodes[prime_variable - 1], self._new_logistic_psdd(right_vtree), self.rand_gen.random_sample(size=(self._num_classes, )), )) elements.append( AndGate( self._terminal_nodes[self._num_variables + prime_variable - 1], self._new_logistic_psdd(right_vtree), self.rand_gen.random_sample(size=(self._num_classes, )), )) for element in elements: element.splittable_variables = copy.deepcopy( right_vtree.variables) elif right_vtree.is_leaf(): elements.append( AndGate( self._new_logistic_psdd(left_vtree), self._terminal_nodes[sub_variable - 1], self.rand_gen.random_sample(size=(self._num_classes, )), )) elements.append( AndGate( self._new_logistic_psdd(left_vtree), self._terminal_nodes[self._num_variables + sub_variable - 1], self.rand_gen.random_sample(size=(self._num_classes, )), )) for element in elements: element.splittable_variables = copy.deepcopy( left_vtree.variables) else: elements.append( AndGate( self._new_logistic_psdd(left_vtree), self._new_logistic_psdd(right_vtree), self.rand_gen.random_sample(size=(self._num_classes, )), )) elements[0].splittable_variables = copy.deepcopy(vtree.variables) root = OrGate(self._largest_index, vtree, elements) self._largest_index += 1 return root
def load(self, f): # read the format at the beginning line = f.readline() while line[0] == "c": line = f.readline() # serialize the vtree vtree_nodes = dict() unvisited_vtree_nodes = deque() unvisited_vtree_nodes.append(self._vtree) while len(unvisited_vtree_nodes): node = unvisited_vtree_nodes.popleft() vtree_nodes[node.index] = node if not node.is_leaf(): unvisited_vtree_nodes.append(node.left) unvisited_vtree_nodes.append(node.right) # extract the saved logistic circuit nodes = dict() line = f.readline() while line[0] == "T" or line[0] == "F": line_as_list = line.strip().split(" ") positive_literal, var = (line_as_list[0] == "T"), int( line_as_list[3]) index, vtree_index = int(line_as_list[1]), int(line_as_list[2]) parameters = [] for i in range(self._num_classes): parameters.append(float(line_as_list[4 + i])) parameters = np.array(parameters, dtype=np.float64) if positive_literal: nodes[index] = (CircuitTerminal(index, vtree_nodes[vtree_index], var, LITERAL_IS_TRUE, parameters), {var}) else: nodes[index] = (CircuitTerminal(index, vtree_nodes[vtree_index], var, LITERAL_IS_FALSE, parameters), {-var}) self._largest_index = max(self._largest_index, index) line = f.readline() self._terminal_nodes = [x[0] for x in nodes.values()] self._terminal_nodes.sort(key=lambda x: (-x.var_value, x.var_index)) if len(self._terminal_nodes) != 2 * self._num_variables: raise ValueError( "Number of terminal nodes recorded in the circuit file " "does not match 2 * number of variables in the provided vtree." ) root = None while line[0] == "D": line_as_list = line.strip().split(" ") index, vtree_index, num_elements = int(line_as_list[1]), int( line_as_list[2]), int(line_as_list[3]) elements = [] variables = set() for i in range(num_elements): prime_index = int(line_as_list[i * (self._num_classes + 2) + 4].strip("(")) sub_index = int(line_as_list[i * (self._num_classes + 2) + 5]) element_variables = nodes[prime_index][1].union( nodes[sub_index][1]) variables = variables.union(element_variables) splittable_variables = set() for variable in element_variables: if -variable in element_variables: splittable_variables.add(abs(variable)) parameters = [] for j in range(self._num_classes): parameters.append( float(line_as_list[i * (self._num_classes + 2) + 6 + j].strip(")"))) parameters = np.array(parameters, dtype=np.float64) elements.append( AndGate(nodes[prime_index][0], nodes[sub_index][0], parameters)) elements[-1].splittable_variables = splittable_variables nodes[index] = (OrGate(index, vtree_nodes[vtree_index], elements), variables) root = nodes[index][0] self._largest_index = max(self._largest_index, index) line = f.readline() if line[0] != "B": raise ValueError( "The last line in a circuit file must record the bias parameters." ) self._bias = np.array([float(x) for x in line.strip().split(" ")[1:]], dtype=np.float64) gc.collect() return root