def update(self, orig_geom=None, inputs=None):

        if orig_geom is not None:
            self.orig_geom = orig_geom

        if inputs is not None:
            self.inputs = inputs

        for name in self.graph.nodes():
            self.graph.node[name]["evaluated"] = False  # flag all nodes as unevaluated

        self.set_input_node_states(self.inputs)  # reset the inputs

        for name in self.output_node_names:
            self.graph.node[name]["state"] = 0.0  # clear old outputs
            self.graph.node[name]["state"] = self.calc_node_state(name)  # calculate new outputs

        loc = [0, 0, 0]
        for n, name in enumerate(self.output_node_names[:3]):
            loc[n] = self.size[n] * (0.5*self.graph.node[name]["state"] + 0.5)

        # print self.size
        # print "loc: ", loc

        # new geometry: just a single patch different from original geometry
        self.values, _ = add_patch(self.orig_geom, loc=loc, mat=self.patch_mat)
    def mutate(self, rate=None):

        if self.patch_mode:
            self.values, sub_vox_dict = add_patch(self.values)

            for parent, child in sub_vox_dict.items():
                self.sub_vox_dict[parent] = [child]

            return "patched", 1

        else:
            if rate is None:
                rate = self.p

            scale = self.scale
            if self.scale is None:
                scale = np.abs(1 / self.values)
                # scale = np.clip(self.values**0.5, self.start_value**0.5, self.upper_bound)
                # this was for meta mutations

            selection = np.random.random(self.size) < rate
            selection = np.logical_and(selection, self.mutable_vox)

            if self.vox_options is not None:
                change = np.random.choice(self.vox_options, self.size)
                self.values[selection] = change[selection]
            else:
                change = np.random.normal(scale=scale, size=self.size)
                self.values[selection] += change[selection]

            self.values = np.clip(self.values, self.lower_bound,
                                  self.upper_bound)

            self.enforce_symmetry()

            self.regulate_sub_voxels()

            if self.func is not None:
                self.values = self.func(self.values)

            return "gaussian", self.scale
    def update(self, orig_geom=None, inputs=None, loc=None):

        if loc is not None:
            self.values, _ = add_patch(orig_geom, loc=loc, mat=self.patch_mat)
            return

        if orig_geom is not None:
            self.orig_geom = orig_geom

        if self.already_patched or self.freeze:
            self.values = self.orig_geom
            return

        if inputs is not None:
            self.input_layer = inputs + [1.0]*self.has_input_bias

        # track weight index
        w = 0

        if len(self.hidden_layer) > 0:

            # hidden layer
            new_hidden_layer = [0]*(len(self.hidden_layer) - self.has_hidden_bias)
            for h in range(len(new_hidden_layer)):
                for i in range(len(self.input_layer)):
                    new_hidden_layer[h] += self.input_layer[i] * self.weights[w]
                    w += 1

            self.hidden_layer = list(np.tanh(new_hidden_layer)) + [1.0]*self.has_hidden_bias

            # output layer
            new_output_layer = [0]*len(self.output_layer)
            for o in range(len(new_output_layer)):
                for h in range(len(self.hidden_layer)):
                    new_output_layer[o] += self.hidden_layer[h] * self.weights[w]
                    w += 1

            self.output_layer = np.tanh(new_output_layer)

        elif self.evo_strategies:
            self.output_layer = self.weights

        else:  # no hidden layer input goes straight to output

            # output layer
            new_output_layer = [0]*len(self.output_layer)
            for o in range(len(new_output_layer)):
                for i in range(len(self.input_layer)):
                    new_output_layer[o] += self.input_layer[i] * self.weights[w]
                    w += 1

            self.output_layer = np.tanh(new_output_layer)

        shifted_output = 0.5*self.output_layer+0.5

        # if self.evo_strategies:
        #     w = 3
        #     shifted_output = 0.5*shifted_output+0.2
        #
        #     if self.input_layer[0] == 0:
        #         shifted_output[0] = 1-(shifted_output[0]+0.1)
        #         shifted_output[1] = 1-(shifted_output[1]+0.1)
        #
        #     if self.input_layer[0] == 1:
        #         shifted_output[0] = 1-(shifted_output[0]+0.1)
        #
        #     if self.input_layer[0] == 2:
        #         shifted_output[1] = 1-(shifted_output[1]+0.1)

        loc = [0, 0, 0]
        for i in range(3):
            loc[i] = self.size[i]*shifted_output[i]

        # new geometry: just a single patch different from original geometry
        self.values, _ = add_patch(self.orig_geom, loc=loc, mat=self.patch_mat)

        if w < len(self.weights):
            n = len(self.weights) - w
            print "only need the first {0} weights (deleting the extra {1})".format(w, n)
            self.weights = self.weights[:w]