예제 #1
0
def boundEqConflict():
    '''
    Simple presecion exmaple.
    Only two nodes that are conncted with ReLU, and an equation that asks if the ReLU output is very small negative
    :return:
    '''
    network = MarabouCore.InputQuery()
    network.setNumberOfVariables(2)

    network.setLowerBound(0, -5)
    network.setUpperBound(0, 5)

    network.setLowerBound(1, 0)
    network.setUpperBound(1, 5)

    MarabouCore.addReluConstraint(network, 0, 1)

    eq = MarabouCore.Equation(MarabouCore.Equation.LE)
    eq.addAddend(1, 1)
    eq.setScalar(-10**-4)  # -10 ** -4 works
    network.addEquation(eq)

    verbose = 2
    vars1, stats1 = MarabouCore.solve(network, "", 0, verbose)
    if len(vars1) > 0:
        print("SAT")
        print(vars1)
        return False
    else:
        print("UNSAT")
        return True
예제 #2
0
def add_hidden_state_equations(inputQuery, variables_first_index, input_weight, hidden_weight, num_iterations):
    '''
    add all hidden state equations:
        input_weight * x1 = s1b
        for each k > 1
            input_weight * xi + hidden_weight * s(k-1)f = sib
        and ReLu's
    :param inputQuery: query to append to
    :param variables_first_index: the first index of the hidden vector variable
    :param input_weight: the weight in the input
    :param hidden_weight: the weight for the hidden vector
    :param num_iterations: number of iterations
    :return:
    '''
    equation1 = MarabouCore.Equation()
    equation1.addAddend(input_weight, 0)
    equation1.addAddend(-1, variables_first_index)
    equation1.setScalar(0)
    inputQuery.addEquation(equation1)

    for k in range(1, num_iterations):
        cur_equation = MarabouCore.Equation()
        cur_equation.addAddend(input_weight, k)  # xk
        cur_equation.addAddend(hidden_weight, variables_first_index + (2 * k) - 1)  # s(k-1)f
        cur_equation.addAddend(-1, variables_first_index + (2 * k))  # skb
        cur_equation.setScalar(0)
        inputQuery.addEquation(cur_equation)

    # ReLu's
    for k in range(variables_first_index, variables_first_index + 2 * num_iterations, 2):
        MarabouCore.addReluConstraint(inputQuery, k, k + 1)
예제 #3
0
def add_output_equations(network, rnn_output_idxs, output_weight, output_bias):
    '''
    build equations for the output
    :param network: network to append equations and variables to
    :param rnn_output_idxs: the output indices of the previous layer
    :param output_weight: Weights to multiply the previous layer
    :param output_bias: The bias of each equation
    :return: list of indices of output classes
    '''
    assert (len(rnn_output_idxs) == output_weight.shape[1])
    assert (output_weight.shape[0] == len(output_bias))
    last_idx = network.getNumberOfVariables()
    output_idxs = []
    network.setNumberOfVariables(
        last_idx + (output_weight.shape[0] * 2))  # *2 because of the relu
    for i in range(output_weight.shape[0]):
        b_variable_idx = last_idx + (2 * i)
        f_variable_idx = last_idx + 1 + (2 * i)
        output_idxs.append(f_variable_idx)

        network.setLowerBound(b_variable_idx, -large)
        network.setUpperBound(b_variable_idx, large)
        network.setLowerBound(f_variable_idx, 0)
        network.setUpperBound(f_variable_idx, large)
        MarabouCore.addReluConstraint(network, b_variable_idx, f_variable_idx)

        output_eq = MarabouCore.Equation()
        for j in range(output_weight.shape[1]):
            output_eq.addAddend(output_weight[i, j], rnn_output_idxs[j])

        output_eq.addAddend(-1, b_variable_idx)
        output_eq.setScalar(-output_bias[i])
        network.addEquation(output_eq)

    return output_idxs
예제 #4
0
파일: tests.py 프로젝트: zeta1999/Marabou
def define_network():
    network = MarabouCore.InputQuery()
    network.setNumberOfVariables(3)

    # x
    network.setLowerBound(0, -1)
    network.setUpperBound(0, 1)

    network.setLowerBound(1, 1)
    network.setUpperBound(1, 2)

    # y
    network.setLowerBound(2, -large)
    network.setUpperBound(2, large)

    MarabouCore.addReluConstraint(network, 0, 1)

    # y - relu(x) >= 0
    output_equation = MarabouCore.Equation()
    output_equation.addAddend(1, 2)
    output_equation.addAddend(-1, 1)
    output_equation.setScalar(0)
    # output_equation.dump()
    network.addEquation(output_equation)

    # y <= n * 0.01
    property_eq = MarabouCore.Equation(MarabouCore.Equation.LE)
    property_eq.addAddend(1, 1)
    property_eq.setScalar(3)

    return network
예제 #5
0
        def add_intermediate_layer_equations():
            first_idx = self.network.getNumberOfVariables()
            # times 2 for the b and f variables
            self.network.setNumberOfVariables(first_idx + (output_weights.shape[1] * 2))
            b_indices = range(first_idx, first_idx + (output_weights.shape[1] * 2), 2)
            f_indices = range(first_idx + 1, first_idx + (output_weights.shape[1] * 2), 2)
            for i in range(output_weights.shape[1]):
                cur_b_idx = b_indices[i]
                cur_f_idx = f_indices[i]
                # b variable
                self.network.setLowerBound(cur_b_idx, -LARGE)
                self.network.setUpperBound(cur_b_idx, LARGE)
                # f variable
                self.network.setLowerBound(cur_f_idx, 0)
                self.network.setUpperBound(cur_f_idx, LARGE)

                MarabouCore.addReluConstraint(self.network, cur_b_idx, cur_f_idx)
                # b equation
                eq = MarabouCore.Equation()
                for j, w in enumerate(output_weights[:, i]):
                    eq.addAddend(w, prev_layer_idx[j])
                eq.setScalar(-output_bias_weights[i])
                eq.addAddend(-1, cur_b_idx)
                self.network.addEquation(eq)
            return f_indices
예제 #6
0
def define_positive_sum_network(xlim=(-1, 1)):
    '''
    Defines the positive_sum network in a marabou way, without the recurrent part
    i.e. we define:
        s_i b = s_i-1 f + x_i
        y = s_i f
    :param xlim: how to limit the input to the network
    :return: query to marabou that defines the positive_sum rnn network (without recurent)
    '''
    num_params_for_cell = 5

    # Plus one is for the invariant proof, we will add a slack variable
    positive_sum_rnn_query = MarabouCore.InputQuery()
    positive_sum_rnn_query.setNumberOfVariables(num_params_for_cell)  # + extra_params)

    # x
    positive_sum_rnn_query.setLowerBound(0, xlim[0])
    positive_sum_rnn_query.setUpperBound(0, xlim[1])

    # s_i-1 f (or temp in some of my notes)
    positive_sum_rnn_query.setLowerBound(1, 0)
    positive_sum_rnn_query.setUpperBound(1, large)

    # s_i b
    positive_sum_rnn_query.setLowerBound(2, -large)
    positive_sum_rnn_query.setUpperBound(2, large)

    # s_i f
    positive_sum_rnn_query.setLowerBound(3, 0)
    positive_sum_rnn_query.setUpperBound(3, large)

    # y
    positive_sum_rnn_query.setLowerBound(4, -large)
    positive_sum_rnn_query.setUpperBound(4, large)

    # s_i b = x_i * 1 + s_i-1 f * 1
    update_eq = MarabouCore.Equation()
    update_eq.addAddend(1, 0)
    update_eq.addAddend(1, 1)
    update_eq.addAddend(-1, 2)
    update_eq.setScalar(0)
    # update_eq.dump()
    positive_sum_rnn_query.addEquation(update_eq)

    # s_i f = ReLu(s_i b)
    MarabouCore.addReluConstraint(positive_sum_rnn_query, 2, 3)

    # y - skf  = 0
    output_equation = MarabouCore.Equation()
    output_equation.addAddend(1, 4)
    output_equation.addAddend(-1, 3)
    output_equation.setScalar(0)
    # output_equation.dump()
    positive_sum_rnn_query.addEquation(output_equation)

    return positive_sum_rnn_query
예제 #7
0
    def getMarabouQuery(self):
        """Function to convert network into Marabou InputQuery

        Returns:
            :class:`~maraboupy.MarabouCore.InputQuery`
        """
        ipq = MarabouCore.InputQuery()
        ipq.setNumberOfVariables(self.numVars)

        i = 0
        for inputVarArray in self.inputVars:
            for inputVar in inputVarArray.flatten():
                ipq.markInputVariable(inputVar, i)
                i += 1

        i = 0
        for outputVar in self.outputVars.flatten():
            ipq.markOutputVariable(outputVar, i)
            i += 1

        for e in self.equList:
            eq = MarabouCore.Equation(e.EquationType)
            for (c, v) in e.addendList:
                assert v < self.numVars
                eq.addAddend(c, v)
            eq.setScalar(e.scalar)
            ipq.addEquation(eq)

        for r in self.reluList:
            assert r[1] < self.numVars and r[0] < self.numVars
            MarabouCore.addReluConstraint(ipq, r[0], r[1])

        for m in self.maxList:
            assert m[1] < self.numVars
            for e in m[0]:
                assert e < self.numVars
            MarabouCore.addMaxConstraint(ipq, m[0], m[1])

        for b, f in self.absList:
            MarabouCore.addAbsConstraint(ipq, b, f)

        for b, f in self.signList:
            MarabouCore.addSignConstraint(ipq, b, f)

        for disjunction in self.disjunctionList:
            MarabouCore.addDisjunctionConstraint(ipq, disjunction)

        for l in self.lowerBounds:
            assert l < self.numVars
            ipq.setLowerBound(l, self.lowerBounds[l])

        for u in self.upperBounds:
            assert u < self.numVars
            ipq.setUpperBound(u, self.upperBounds[u])

        return ipq
예제 #8
0
    def getMarabouQuery(self):
        """
        Function to convert network into Marabou Query
        Returns:
            ipq: (MarabouCore.InputQuery) representing query
        """
        ipq = MarabouCore.InputQuery()
        ipq.setNumberOfVariables(self.numVars)
        print("num vars = ", self.numVars)
        i = 0
        # TODO: this is necessary, so IF should be added (if user define -> use the userdefined, else use regular inputs)
        if len(self.userDefineInputVars) > 0:
            for inputVar in self.userDefineInputVars:
                ipq.markInputVariable(inputVar, i)
                i += 1
                print("userDefineInputVar", inputVar)
        else:
            for inputVarArray in self.inputVars:
                for inputVar in inputVarArray.flatten():
                    # ipq.markInputVariable(inputVar, i)
                    i += 1
                    print("inputVar", inputVar)

        i = 0
        for outputVar in self.outputVars.flatten():
            ipq.markOutputVariable(outputVar, i)
            i += 1
            print("outputVar", outputVar)

        for e in self.equList:
            eq = MarabouCore.Equation(e.EquationType)
            for (c, v) in e.addendList:
                assert v < self.numVars
                eq.addAddend(c, v)
            eq.setScalar(e.scalar)
            ipq.addEquation(eq)

        for r in self.reluList:
            assert r[1] < self.numVars and r[0] < self.numVars
            MarabouCore.addReluConstraint(ipq, r[0], r[1])

        for m in self.maxList:
            assert m[1] < self.numVars
            for e in m[0]:
                assert e < self.numVars
            MarabouCore.addMaxConstraint(ipq, m[0], m[1])

        for l in self.lowerBounds:
            assert l < self.numVars
            ipq.setLowerBound(l, self.lowerBounds[l])

        for u in self.upperBounds:
            assert u < self.numVars
            ipq.setUpperBound(u, self.upperBounds[u])

        return ipq
예제 #9
0
def add_rnn_cell(query,
                 input_weights,
                 hidden_weight,
                 num_iterations,
                 bias=0,
                 print_debug=False):
    '''
    Create rnn cell --> add 4 parameters to the query and the equations that describe the cell
    The added parameters are (same order): i, s_i-1 f, s_i b, s_i f
    :param query: the network so far (will add to this)
    :param input_weights: list of tuples, each tuple (variable_idx, weight)
    :param hidden_weight: the weight inside the cell
    :param num_iterations: Number of iterations the cell runs
    :return: the index of the last parameter (which is the output of the cell)
    '''

    last_idx = query.getNumberOfVariables()
    query.setNumberOfVariables(last_idx + 4)  # i, s_i-1 f, s_i b, s_i f

    # i
    # TODO: when doing this we make the number of iterations to be n_iterations + 1
    query.setLowerBound(last_idx, 0)
    query.setUpperBound(last_idx, num_iterations)

    # s_i-1 f
    query.setLowerBound(last_idx + 1, 0)
    query.setUpperBound(last_idx + 1, large)

    # s_i b
    query.setLowerBound(last_idx + 2, -large)
    query.setUpperBound(last_idx + 2, large)

    # s_i f
    query.setLowerBound(last_idx + 3, 0)
    query.setUpperBound(last_idx + 3, large)

    # s_i f = ReLu(s_i b)
    MarabouCore.addReluConstraint(query, last_idx + 2, last_idx + 3)

    # s_i-1 f >= i * \sum (x_j_min * w_j)
    # prev_min_eq = MarabouCore.Equation(MarabouCore.Equation.LE)
    # prev_min_eq.addAddend(1, last_idx + 1)
    # prev_min_eq.addAddend(1, last_idx + 1)

    # s_i b = x_j * w_j for all j connected + s_i-1 f * hidden_weight
    update_eq = MarabouCore.Equation()
    for var_idx, weight in input_weights:
        update_eq.addAddend(weight, var_idx)
    update_eq.addAddend(hidden_weight, last_idx + 1)
    update_eq.addAddend(-1, last_idx + 2)
    update_eq.setScalar(-bias)
    # if print_debug:
    #     update_eq.dump()
    query.addEquation(update_eq)

    return last_idx + 3
예제 #10
0
 def assert_relu_constraint(self, relu):
     if len(np.array(relu.varin).flatten()) > 1:
         print("ERROR: relu.varin is not scalar! It has length",
               len(relu.varin))
         raise NotImplementedError
     else:  # truly, the ok case
         self.num_relu += 1
         MarabouCore.addReluConstraint(self.ipq,
                                       self.get_new_var(relu.varin),
                                       self.get_new_var(relu.varout))
예제 #11
0
    def getMarabouQuery(self):
        """
        Function to convert network into Marabou Query
        Returns:
            ipq: (MarabouCore.InputQuery) representing query
        """
        ipq = MarabouCore.InputQuery()
        ipq.setNumberOfVariables(self.numVars)

        i = 0
        for inputVarArray in self.inputVars:
            for inputVar in inputVarArray.flatten():
                ipq.markInputVariable(inputVar, i)
                i += 1

        i = 0
        for outputVar in self.outputVars.flatten():
            ipq.markOutputVariable(outputVar, i)
            i += 1

        for e in self.equList:
            eq = MarabouCore.Equation(e.EquationType)
            for (c, v) in e.addendList:
                assert v < self.numVars
                eq.addAddend(c, v)
            eq.setScalar(e.scalar)
            ipq.addEquation(eq)

        for r in self.reluList:
            assert r[1] < self.numVars and r[0] < self.numVars
            MarabouCore.addReluConstraint(ipq, r[0], r[1])

        for m in self.maxList:
            assert m[1] < self.numVars
            for e in m[0]:
                assert e < self.numVars
            MarabouCore.addMaxConstraint(ipq, m[0], m[1])

        for l in self.lowerBounds:
            assert l < self.numVars
            ipq.setLowerBound(l, self.lowerBounds[l])

        for u in self.upperBounds:
            assert u < self.numVars
            ipq.setUpperBound(u, self.upperBounds[u])

        for i, var in enumerate(self.inputVars[0]):
            ipq.markInputVariable(i, var)
        for i, var in enumerate(self.outputVars[0]):
            ipq.markOutputVariable(i, var)

        return ipq
예제 #12
0
def define_ipq(property_bound):
    """
    This function defines a simple input query directly through MarabouCore
    Arguments:
        property_bound: (float) value of upper bound for x + y
    Returns:
        ipq (MarabouCore.InputQuery) input query object representing network and constraints
    """
    ipq = MarabouCore.InputQuery()
    ipq.setNumberOfVariables(3)

    # x
    ipq.setLowerBound(0, -1)
    ipq.setUpperBound(0, 1)

    # relu(x)
    ipq.setLowerBound(1, 0)
    ipq.setUpperBound(1, LARGE)

    # y
    ipq.setLowerBound(2, -LARGE)
    # if an upper/lower bound is not supplied to Marabou, Marabou uses float min/max

    MarabouCore.addReluConstraint(ipq, 0, 1)

    # y - relu(x) = 0
    output_equation = MarabouCore.Equation()
    output_equation.addAddend(1, 2)
    output_equation.addAddend(-1, 1)
    output_equation.setScalar(0)
    ipq.addEquation(output_equation)

    # x + y <= property_bound
    property_eq = MarabouCore.Equation(MarabouCore.Equation.LE)
    property_eq.addAddend(1, 0)
    property_eq.addAddend(1, 2)
    property_eq.setScalar(property_bound)
    ipq.addEquation(property_eq)
    return ipq
예제 #13
0
    def getMarabouQuery(self):
        """
        Function to convert network into Marabou Query
        Returns:
            ipq: (MarabouCore.InputQuery) representing query
        """
        ipq = MarabouCore.InputQuery()
        ipq.setNumberOfVariables(self.numVars)

        for e in self.equList:
            eq = MarabouCore.Equation(e.EquationType)
            for (c, v) in e.addendList:
                assert v < self.numVars
                eq.addAddend(c, v)
            eq.setScalar(e.scalar)
            ipq.addEquation(eq)

        for r in self.reluList:
            assert r[1] < self.numVars and r[0] < self.numVars
            MarabouCore.addReluConstraint(ipq, r[0], r[1])

        for m in self.maxList:
            assert m[1] < self.numVars
            for e in m[0]:
                assert e < self.numVars
            MarabouCore.addMaxConstraint(ipq, m[0], m[1])

        for l in self.lowerBounds:
            assert l < self.numVars
            ipq.setLowerBound(l, self.lowerBounds[l])

        for u in self.upperBounds:
            assert u < self.numVars
            ipq.setUpperBound(u, self.upperBounds[u])

        return ipq
예제 #14
0
equation1 = MarabouCore.Equation()
equation1.addAddend(1, 0)
equation1.addAddend(-1, 1)
equation1.setScalar(0)
inputQuery.addEquation(equation1)

equation2 = MarabouCore.Equation()
equation2.addAddend(1, 0)
equation2.addAddend(1, 3)
equation2.setScalar(0)
inputQuery.addEquation(equation2)

equation3 = MarabouCore.Equation()
equation3.addAddend(1, 2)
equation3.addAddend(1, 4)
equation3.addAddend(-1, 5)
equation3.setScalar(0)
inputQuery.addEquation(equation3)

MarabouCore.addReluConstraint(inputQuery, 1, 2)
MarabouCore.addReluConstraint(inputQuery, 3, 4)

options = createOptions()
vars1, stats1 = MarabouCore.solve(inputQuery, options, "")
if len(vars1) > 0:
    print("SAT")
    print(vars1)
else:
    print("UNSAT")
예제 #15
0
def define_sum_network(xlim=(-1, 1)):
    '''
    Defines the sum network in a marabou way, without the recurrent part
    i.e. we define:
        s_i b = s_i-1 f + x_i
        y = s_i f
    :param xlim: how to limit the input to the network
    :return: query to marabou that defines the sum rnn network (without recurent)
    '''
    num_params_for_cell = 8

    sum_rnn_query = MarabouCore.InputQuery()
    sum_rnn_query.setNumberOfVariables(num_params_for_cell)

    # x
    sum_rnn_query.setLowerBound(0, xlim[0])
    sum_rnn_query.setUpperBound(0, xlim[1])

    # s_i-1 f (or temp in some of my notes)
    sum_rnn_query.setLowerBound(1, 0)
    sum_rnn_query.setUpperBound(1, large)

    # s_i b
    sum_rnn_query.setLowerBound(2, -large)
    sum_rnn_query.setUpperBound(2, large)

    # s_i f
    sum_rnn_query.setLowerBound(3, 0)
    sum_rnn_query.setUpperBound(3, large)

    # z_i-1 f
    sum_rnn_query.setLowerBound(4, 0)
    sum_rnn_query.setUpperBound(4, large)

    # z_i b
    sum_rnn_query.setLowerBound(5, -large)
    sum_rnn_query.setUpperBound(5, large)

    # z_i f
    sum_rnn_query.setLowerBound(6, 0)
    sum_rnn_query.setUpperBound(6, large)

    # y
    sum_rnn_query.setLowerBound(7, -large)
    sum_rnn_query.setUpperBound(7, large)

    # s_i b = x_i * 1 + s_i-1 f * 1
    update_eq = MarabouCore.Equation()
    update_eq.addAddend(1, 0)
    update_eq.addAddend(1, 1)
    update_eq.addAddend(-1, 2)
    update_eq.setScalar(0)
    sum_rnn_query.addEquation(update_eq)

    # s_i f = ReLu(s_i b)
    MarabouCore.addReluConstraint(sum_rnn_query, 2, 3)

    # z_i b = -x_i + z_i-1 f
    update_eq = MarabouCore.Equation()
    update_eq.addAddend(-1, 0)
    update_eq.addAddend(1, 4)
    update_eq.addAddend(-1, 5)
    update_eq.setScalar(0)
    sum_rnn_query.addEquation(update_eq)

    # z_i f = ReLu(z_i b)
    MarabouCore.addReluConstraint(sum_rnn_query, 5, 6)

    # - y + skf  + zkf = 0
    output_equation = MarabouCore.Equation()
    output_equation.addAddend(1, 3)
    output_equation.addAddend(1, 6)
    output_equation.addAddend(-1, 7)
    output_equation.setScalar(0)
    sum_rnn_query.addEquation(output_equation)

    return sum_rnn_query
예제 #16
0
def add_rnn_multidim_cells(query, input_idx, input_weights, hidden_weights, bias, num_iterations, print_debug=False):
    '''
    Create n rnn cells, where n is hidden_weights.shape[0] == hidden_weights.shape[1] ==  len(bias)
    The added parameters are (same order): i, s_i-1 f, s_i b, s_i f for each of the n added cells (i.e. adding 4*n variables)
    :param query: the network so far (will add to this)
    :param input_idx: list of input id's, length m
    :param input_weights: matrix of input weights, size m x n
    :param hidden_weights: matrix of weights
    :param bias: vector of biases to add to each equation, length should be n, if None use 0 bias
    :param num_iterations: Number of iterations
    :return: list of output cells, the length will be the same n
    '''
    assert type(hidden_weights) == np.ndarray
    assert len(hidden_weights.shape) == 2
    assert hidden_weights.shape[0] == hidden_weights.shape[1]
    assert len(input_idx) == input_weights.shape[1], "{}, {}".format(len(input_idx), input_weights.shape[1])
    assert hidden_weights.shape[0] == input_weights.shape[0]

    n = hidden_weights.shape[0]

    if bias is None:
        bias = [0] * n
    else:
        assert len(bias) == n
    last_idx = query.getNumberOfVariables()
    prev_iteration_idxs = [i + 1 for i in range(last_idx, last_idx + (4 * n), 4)]
    output_idxs = [i + 3 for i in range(last_idx, last_idx + (4 * n), 4)]
    query.setNumberOfVariables(last_idx + (4 * n))  # i, s_i-1 f, s_i b, s_i f

    cell_idx = last_idx
    for i in range(n):
        # i
        query.setLowerBound(cell_idx, 0)
        # we bound the memory unit, and num_iterations is for the output which is doing one more calculation
        query.setUpperBound(cell_idx, num_iterations - 1)

        # s_i-1 f
        query.setLowerBound(cell_idx + 1, 0)
        query.setUpperBound(cell_idx + 1, LARGE)

        # s_i b
        query.setLowerBound(cell_idx + 2, -LARGE)
        query.setUpperBound(cell_idx + 2, LARGE)

        # s_i f
        query.setLowerBound(cell_idx + 3, 0)
        query.setUpperBound(cell_idx + 3, LARGE)

        # s_i f = ReLu(s_i b)
        MarabouCore.addReluConstraint(query, cell_idx + 2, cell_idx + 3)

        # s_i-1 f >= i * \sum (x_j_min * w_j)
        # prev_min_eq = MarabouCore.Equation(MarabouCore.Equation.LE)
        # prev_min_eq.addAddend(1, last_idx + 1)
        # prev_min_eq.addAddend(1, last_idx + 1)

        # s_i b = x_j * w_j for all j connected + s_i-1 f * hidden_weight
        update_eq = MarabouCore.Equation()
        for j in range(len(input_weights[i, :])):
            w = input_weights[i, j]  # round(input_weights[i, j], 2)
            update_eq.addAddend(w, input_idx[j])

        for j, w in enumerate(hidden_weights[i, :]):
            # w = round(w, 2)
            update_eq.addAddend(w, prev_iteration_idxs[j])

        update_eq.addAddend(-1, cell_idx + 2)
        update_eq.setScalar(-bias[i])
        # if print_debug:
        #     update_eq.dump()
        query.addEquation(update_eq)
        cell_idx += 4

    return output_idxs