Ejemplo n.º 1
0
def _encode_input(image, z3_mask, window_size):
  """Encodes the image pixels by multiplying them with masking variables.

  Converts the pixels into z3.ExprRef by multiplying them with their
  corresponding masking variable. For an image with pixels with the same
  spatial dimensions are multiplied with the same masking variable.

  Args:
    image: float numpy array with shape
        (image_edge_length, image_edge_length, image_channels), image.
    z3_mask: list of z3.ExprRef with length (edge_length // window_size) ** 2,
        unique masking variables.
    window_size: int, side length of the square mask.

  Returns:
    list of list of list of z3.ExprRef with dimensions
        (image_channels, image_edge_length, image_edge_length), encoded input.
  """
  image_edge_length, _, image_channels = image.shape
  encoded_input = []
  for channel in range(image_channels):
    # Slicing the image across each channel
    encoded_input_per_channel = []
    for image_row in range(image_edge_length):
      encoded_input_row = []
      for image_column in range(image_edge_length):
        index = utils.convert_pixel_to_mask_index(
            edge_length=image_edge_length,
            window_size=window_size,
            flattened_pixel_index=image_row * image_edge_length + image_column)
        encoded_input_row.append(
            z3.ToReal(z3_mask[index]) * image[image_row][image_column][channel])
      encoded_input_per_channel.append(encoded_input_row)
    encoded_input.append(encoded_input_per_channel)
  return encoded_input
Ejemplo n.º 2
0
    def test_formulate_smt_constraints_fully_connected_layer(self):
        # For a neural network with 4 hidden nodes in the first layer, with the
        # original first layer activations = 1, and the SMT encoding of
        # the first hidden nodes- [mask_0, mask_1, mask_2, mask_3]. For
        # masked_activation > delta * original (k such constraints), only k mask
        # bits should be set to 1 and the others to 0.
        image_edge_length = 2
        top_k = np.random.randint(low=1, high=image_edge_length**2)
        z3_mask = [_get_z3_var(index=i) for i in range(image_edge_length**2)]
        smt_first_layer = [1 * z3.ToReal(i) for i in z3_mask]
        nn_first_layer = np.ones(len(smt_first_layer))

        z3_optimizer = utils.ImageOptimizer(z3_mask=z3_mask,
                                            window_size=1,
                                            edge_length=image_edge_length)
        z3_optimizer = masking._formulate_smt_constraints_fully_connected_layer(
            z3_optimizer=z3_optimizer,
            smt_first_layer=smt_first_layer,
            nn_first_layer=nn_first_layer,
            top_k=top_k,
            gamma=np.random.rand())
        mask, result = z3_optimizer._optimize()

        self.assertEqual(result, 'sat')
        self.assertEqual(np.sum(mask), top_k)
Ejemplo n.º 3
0
 def test_smt_forward_equals_nn_forward(self):
     weights = [
         np.random.random_sample((3, 3)),
         np.random.random_sample((1, 3))
     ]
     biases = [np.random.random_sample(3), np.random.random_sample(1)]
     activations = ['relu', 'linear']
     z3_var = z3.Int('var')
     nn_output, _ = utils.nn_forward(np.ones(3), weights, biases,
                                     activations)
     smt_output, _ = utils.smt_forward(
         [z3.ToReal(z3_var),
          z3.ToReal(z3_var),
          z3.ToReal(z3_var)], weights, biases, activations)
     self._assert_z3_constraint_sat(constraint=z3.And(
         smt_output[0] - nn_output[0] < 1e-4,
         smt_output[0] - nn_output[0] > -1e-4),
                                    z3_var=z3_var)
Ejemplo n.º 4
0
    def test_formulate_smt_constraints_convolution_layer_text(self):
        with self.test_session():
            # Temporary graphs should be created inside a session. Notice multiple
            # graphs are being created in this particular code. So, if each graph
            # isn't created inside a separate session, the tensor names will have
            # unwanted integer suffices, which then would cause problems while
            # accessing tensors by name.
            _create_temporary_tf_graph_text_cnn(self.test_model_path)

        # The 1st convolution layer has 12 neurons.
        image = np.ones(5)
        tensor_names = {
            'input': 'input_1:0',
            'embedding': 'embedding/embedding_lookup/Identity_1:0',
            'first_layer': 'conv1d/BiasAdd:0',
            'first_layer_relu': 'conv1d/Relu:0',
            'logits': 'dense/BiasAdd:0',
            'softmax': 'dense/Sigmoid:0',
            'weights_layer_1': 'conv1d/conv1d/ExpandDims_1:0',
            'biases_layer_1': 'conv1d/BiasAdd/ReadVariableOp:0'
        }
        session = utils.restore_model(self.test_model_path)
        cnn_predictions = session.run(
            tensor_names,
            feed_dict={tensor_names['input']: image.reshape(1, 5)})
        text_embedding = masking._remove_batch_axis(
            cnn_predictions['embedding'])
        z3_mask = [
            z3.Int('mask_%d' % i) for i in range(text_embedding.shape[0])
        ]
        masked_input = []
        for mask_bit, embedding_row in zip(z3_mask, text_embedding):
            masked_input.append(
                [z3.ToReal(mask_bit) * i for i in embedding_row])
        first_layer_activations = masking._reorder(
            masking._remove_batch_axis(
                cnn_predictions['first_layer'])).reshape(-1)
        z3_optimizer = masking._formulate_smt_constraints_convolution_layer(
            z3_optimizer=utils.TextOptimizer(z3_mask=z3_mask),
            kernels=masking._reshape_kernels(
                kernels=cnn_predictions['weights_layer_1'],
                model_type='text_cnn'),
            biases=cnn_predictions['biases_layer_1'],
            chosen_indices=first_layer_activations.argsort()[-5:],
            conv_activations=first_layer_activations,
            input_activation_maps=[masked_input],
            output_activation_map_shape=masking._get_activation_map_shape(
                activation_maps_shape=cnn_predictions['first_layer'].shape,
                model_type='text_cnn'),
            strides=1,
            padding=(0, 0),
            gamma=0.5)
        mask, result = z3_optimizer.generate_mask()

        self.assertEqual(result, 'sat')
        self.assertEqual(mask.shape, (5, ))
        session.close()
Ejemplo n.º 5
0
def _process_text(image, run_params):
  """Generates the masked embedding and does a forward pass of the image.

  Args:
    image: float numpy array with shape (num_words,), text to be masked.
    run_params: RunParams with model_type, model_path, image_placeholder_shape,
        activations, tensor_names, input, first_layer, logits.

  Returns:
    masked_input: nested list of z3.ExprRef with dimensions
      (1, num_words, num_latent_dimensions).
    unmasked_predictions: dict,
      * input: float numpy array, the input tensor to the neural network.
      * first_layer: float numpy array, the first layer tensor in the neural
          network.
      * first_layer_relu: str, the first layer relu activation
          tensor in the neural network.
      * logits: str, the logits tensor in the neural network.
      * softmax: float numpy array, the softmax tensor in the neural network.
      * weights_layer_1: float numpy array, the first layer fc / conv weights.
      * biases_layer_1: float numpy array, the first layer fc / conv biases.
      * (text only) embedding: float numpy array with shape (num_words,
          num_latent_dimensions), the embedding layer.
    session: tf.Session, tensorflow session with the loaded neural network.
    optimizer: utils.TextOptimizer, z3 optimizer for image.
  Raises:
    ValueError: Raises an error if the text isn't a 1D array.
  """
  if image.ndim != 1:
    raise ValueError('The text input should be a 1D numpy array. '
                     'Shape of the received input: %s' % str(image.shape))
  session = utils.restore_model(run_params.model_path)
  unmasked_predictions = session.run(
      run_params.tensor_names, feed_dict={
          run_params.tensor_names['input']: image.reshape(
              run_params.image_placeholder_shape)})

  text_embedding = _remove_batch_axis(unmasked_predictions['embedding'])
  # text_embedding has a shape (num_words, num_latent_dimensions)
  z3_mask = [z3.Int('mask_%d' % i) for i in range(text_embedding.shape[0])]

  # masked_input has a shape (num_words, num_latent_dimensions)
  masked_input = []
  for mask_bit, embedding_row in zip(z3_mask, text_embedding):
    masked_input.append([z3.ToReal(mask_bit) * i for i in embedding_row])

  return ([masked_input], unmasked_predictions, session,
          utils.TextOptimizer(z3_mask=z3_mask))
Ejemplo n.º 6
0
def prepare_solver(instance: Instance) -> Tuple[z3.Solver, Dict[int, str]]:
    solver = z3.Solver()
    variables = []
    ingredient_indices: Dict[str, int] = {}
    ingredient_names: Dict[int, str] = {}
    num_of_meals = len(MEAL_NAMES)
    # create a list of variables for each ingredient
    for ingredient_id in range(len(instance.ingredients)):
        meal_vars = []
        name = instance.ingredients[ingredient_id].name
        ingredient_indices[name] = ingredient_id
        ingredient_names[ingredient_id] = name
        for meal_id in range(num_of_meals):
            var_name = make_variable_name(meal_id, ingredient_id)
            var = z3.Int(var_name)
            solver.add(var >= 0)
            meal_vars.append(z3.ToReal(var))
        variables.append(meal_vars)
    # add constraints for food conflicts
    for food1, food2 in instance.conflicts:
        food1_id = ingredient_indices[food1]
        food2_id = ingredient_indices[food2]
        food1_vars = variables[food1_id]
        food2_vars = variables[food2_id]
        for var1, var2 in zip(food1_vars, food2_vars):
            solver.add(z3.Or(var1 == 0, var2 == 0))
    # add constraints for total amount of substances
    macro_sums = {}
    for macro in instance.macros:
        macro_sums[macro] = 0.0
    for ingredient_vars, ingredient in zip(variables, instance.ingredients):
        ingredient_sum = z3.Sum(ingredient_vars)
        for macro in instance.macros:
            macro_sums[macro] += ingredient_sum * ingredient.macros[macro]
    for target in instance.targets:
        macro_sum = macro_sums[target.macro]
        solver.add(macro_sum >= target.min)
        solver.add(macro_sum <= target.max)
    # ensure that meals are not empty
    num_of_ingredients = len(variables)
    for meal_id in range(num_of_meals):
        meal_conditions = []
        for ingredient_id in range(num_of_ingredients):
            meal_conditions.append(variables[ingredient_id][meal_id] > 0)
        solver.add(z3.Or(meal_conditions))

    return solver, ingredient_names
Ejemplo n.º 7
0
  def test_smt_constraints_final_layer(self):
    # The SMT encoding of the final layer - [mask_0, mask_1, mask_2, mask_3].
    # For logit_label_index > rest, the mask_bit at label_index should be set to
    # 1.
    image_edge_length = 2
    label_index = np.random.randint(low=0, high=image_edge_length ** 2)
    z3_mask = [_get_z3_var(index=i) for i in range(image_edge_length ** 2)]
    smt_output = [1 * z3.ToReal(i) for i in z3_mask]

    z3_optimizer = utils.ImageOptimizer(
        z3_mask=z3_mask, window_size=1, edge_length=image_edge_length)
    z3_optimizer = masking._formulate_smt_constraints_final_layer(
        z3_optimizer=z3_optimizer,
        smt_output=smt_output,
        delta=np.random.rand(),
        label_index=label_index)
    mask, result = z3_optimizer._optimize()

    self.assertEqual(result, 'sat')
    self.assertEqual(mask.reshape(-1)[label_index], 1)
    self.assertEqual(np.sum(mask), 1)
Ejemplo n.º 8
0
def z3_matchLeftAndRight(left,right,op):
    """Appropriately change the two variables so that they can be used in an
    expression
    
    Parameters
    ----------
    left,right : pyObjectManager.Int.Int or pyObjectManager.Real.Real or pyObjectManager.BitVec.BitVec or pyObjectManager.Char.Char
        Objects to be matched
    op : ast.*
        Operation that will be performed


    Returns
    -------
    tuple
        (z3ObjectLeft,z3ObjectRight) tuple of z3 objects that can be used in an expression
    
    
    The purpose of this function is to match two pyObjectManager.* variables to
    a given ast operation element. Z3 needs to have matched types, and this
    call will not only match the objects, but also attempt to concretize input
    wherever possible.

    Example
    -------
    If you want to auto-match BitVector sizes::

        In [1]: import z3, pyState.z3Helpers, ast
    
        In [2]: from pySym.pyObjectManager.BitVec import BitVec

        In [3]: from pySym.pyState import State

        In [4]: state = State()
    
        In [5]: x = BitVec("x",0,16,state=state)

        In [6]: y = BitVec("y",0,32,state=state)
    
        In [7]: l,r = pyState.z3Helpers.z3_matchLeftAndRight(x,y,ast.Add())

        In [8]: s = z3.Solver()

        In [9]: s.add(l + r == 12)

        In [10]: s
        Out[10]: [SignExt(16, 0x@0) + 0y@0 == 12]

        In [11]: s.check()
        Out[11]: sat

    """

    lType = type(left)
    rType = type(right)

    # If it's char, just grab the BitVec object
    if lType is Char:
        left = left.variable
        lType = type(left)
    if rType is Char:
        right = right.variable
        rType = type(right)

    logger.debug("z3_matchLeftAndRight: Called to match {0} and {1}".format(type(left),type(right)))
    needBitVec = True if type(op) in [ast.BitXor, ast.BitAnd, ast.BitOr, ast.LShift, ast.RShift] else False
    # TODO: If the two sizes are different, we'll have problems down the road.
    bitVecSize = max([c.size for c in [b for b in [left,right] if type(b) is BitVec]],default=Z3_DEFAULT_BITVEC_SIZE)

    #####################################
    # Case: Both are already BitVectors #
    #####################################
    # Check length. Extend if needed.
    if type(left) is BitVec and type(right) is BitVec:
        logger.debug("z3_matchLeftAndRight: Matching BitVecLength @ {0} (left={1},right={2})".format(bitVecSize,left.size,right.size))
        if left.size < right.size:
            # Sign extend left's value to match
            left = z3.SignExt(right.size-left.size,left.getZ3Object())
            right = right.getZ3Object()
        elif right.size > left.size:
            right = z3.SignExt(left.size-right.size,right.getZ3Object())
            left = left.getZ3Object()
        
        # Sync-up the output variables
        left = left.getZ3Object() if type(left) in [Int, Real, BitVec] else left
        right = right.getZ3Object() if type(right) in [Int, Real, BitVec] else right

        logger.debug("z3_matchLeftAndRight: Returning {0} and {1}".format(type(left),type(right)))

        return left,right

    #####################################
    # Case: One is BitVec and one isn't #
    #####################################
    # For now only handling casting of int to BV. Not other way around.
    if (lType is BitVec and rType is Int) or (rType is Int and needBitVec):
        # If we need to convert to BitVec and it is a constant, not variable, do so more directly
        if right.isStatic():
            right = z3.BitVecVal(right.getValue(),bitVecSize)
        # Otherwise cast it. Not optimal, but oh well.
        else:
            right = z3_int_to_bv(right.getZ3Object(),size=bitVecSize)

    if (rType is BitVec and lType is Int) or (lType is Int and needBitVec):
        if left.isStatic():
            left = z3.BitVecVal(left.getValue(),bitVecSize)
        else:
            left = z3_int_to_bv(left.getZ3Object(),size=bitVecSize)
        
    ################################
    # Case: One is Int one is Real #
    ################################
    # So long as this isn't modular arithmetic, let's change to Real things
    if lType is Real and rType is Int and type(op) is not ast.Mod:
        if right.isStatic():
            right = z3.RealVal(right.getValue())
        else:
            # TODO: Z3 is really bad at handling these...
            right = z3.ToReal(right.getZ3Object())

    if rType is Real and lType is Int and type(op) is not ast.Mod:
        if left.isStatic():
            left = z3.RealVal(left.getValue())
        else:
            # TODO: Z3 is really bad at handling these...
            left = z3.ToReal(left.getZ3Object())


    ############################################
    # Case: One is Int one is Real for ast.Mod #
    ############################################
    # So long as this isn't modular arithmetic, let's change to Real things
    if lType is Real and rType is Int and type(op) is ast.Mod:
        if left.isStatic():
            leftVal = left.getValue()
            left = z3.IntVal(leftVal)
            if int(leftVal) != leftVal:
                logger.warn("Truncating value for Modular Arithmetic. That may or may not be what was intended!")

        # See if we can swing this the other direction
        elif right.isStatic():
            rightVal = right.getValue()
            right = z3.RealVal(rightVal)
            

    if rType is Real and lType is Int and type(op) is ast.Mod:
        if right.isStatic():
            rightVal = right.getValue()
            right = z3.IntVal(rightVal)
            if int(rightVal) != rightVal:
                logger.warn("Truncating value for Modular Arithmetic. That may or may not be what was intended!")

        # See if we can swing this the other direction
        else:
            left = z3.RealVal(left.getValue())
    
    # Sync-up the output variables
    left = left.getZ3Object() if type(left) in [Int, Real, BitVec] else left
    right = right.getZ3Object() if type(right) in [Int, Real, BitVec] else right

    logger.debug("z3_matchLeftAndRight: Returning {0} and {1}".format(type(left),type(right)))

    return left,right
Ejemplo n.º 9
0
class SimpleParser:
    precedence = (
        ('left', 'ASSIGN'),
        ('right', 'QM', 'COLON'),
        ('left', 'OR'),
        ('left', 'AND'),
        ('left', 'BITOR'),
        ('left', 'BITXOR'),
        ('left', 'BITAND'),
        ('left', 'EQ', 'NEQ'),
        ('left', 'LT', 'GT', 'GTE', 'LTE'),
        ('left', 'LSHIFT', 'RSHIFT'),
        ('left', 'PLUS', 'MINUS'),
        ('left', 'TIME', 'DIVIDE', 'MODULO'),
        ('right', 'MINUS', 'PLUS', 'SIZEOF', 'NOT', 'BITNOT', 'PLUSPLUS', 'MINUSMINUS',
            'INTCASTOR', 'INTARRCASTOR', 'REALCASTOR', 'BOOLCASTOR'),            # Unary minus operator
        ('left', 'LBRACK', 'LPAREN', 'DOT', 'ARROW', 'PLUSPLUS', 'MINUSMINUS'),
    )

    type_switch = {
        'bool': z3.Bool,
        'uchar': z3.Int,
        'uint': z3.Int,
        'ulong': z3.Int,
        'byte': z3.Int,
        'sbyte': z3.Int,
        'ushort': z3.Int,
        'char': z3.Int,
        'int': z3.Int,
        'long': z3.Int,
        'short': z3.Int,
        'float': z3.Real,
        'double': z3.Real,
        'intArray': lambda x: z3.Array(x, z3.IntSort(), z3.IntSort()),
        'realArray': lambda x: z3.Array(x, z3.RealSort(), z3.IntSort()),
        'string': lambda x: z3.Array(x, z3.IntSort(), z3.IntSort()),
        # <-- No clue if correct (04/17/2020)
        'stringArray': lambda x: z3.Array(x, z3.IntSort(), z3.IntSort())
    }

    unary_ops = {
        '!': z3.Not,
        '-': lambda x: -x,
        '+': lambda x: +x,
        # TODO (?): INTARRCASTOR. Look into ArraySort().
        # 'INTARRCASTOR': lambda x: x if x.sort() != z3.ArraySort(z3.IntSort(), z3.IntSort()) else z3.Array(x, z3.IntSort(), z3.IntSort()),
        # 'INTARRCASTOR': None,
        # 'INTCASTOR': lambda x: x if x.sort() != z3.RealSort()  else z3.ToInt(x),
        'INTCASTOR': lambda x: x if isinstance(x, int) else (int(x) if isinstance(x, float) else (x if x.sort() != z3.RealSort() else z3.ToInt(x))),
        'REALCASTOR': lambda x: x if isinstance(x, float) else (float(x) if isinstance(x, int) else (x if x.sort() != z3.IntSort() else z3.ToReal(x)))
        # 'REALCASTOR': lambda x: x if x.sort() != z3.IntSort() else z3.ToReal(x)
    }

    binary_ops = {
        '>': lambda x, y: x > y,
        '>=': lambda x, y: x >= y,
        '<': lambda x, y: x < y,
        '<=': lambda x, y: x <= y,
        '==': lambda x, y: x == y,
        '!=': lambda x, y: x != y,
        '+': lambda x, y: x + y,
        '-': lambda x, y: x - y,
        '*': lambda x, y: x * y,
        '/': lambda x, y: x / y,
        '%': lambda x, y: x % y,
        '||': z3.Or,
        '&&': z3.And,
    }

    tokens = (
        # 'NULL',
        'INT',  # instant values
        'REAL',
        'CHAR',
        'STRINGS',
        'LBRACK',  # Brackets
        'RBRACK',
        'LPAREN',
        'RPAREN',
        'VARIABLE',
        'DOT',  # Operators
        'ARROW',
        'SIZEOF',
        'GT',
        'GTE',
        'LT',
        'LTE',
        'EQ',
        'NEQ',
        'PLUS',
        'PLUSPLUS',
        'MINUS',
        'MINUSMINUS',
        'TIME',
        'DIVIDE',
        'LSHIFT',
        'RSHIFT',
        'BITAND',
        'BITOR',
        'BITXOR',
        'BITNOT',
        'OR',
        'AND',
        'NOT',
        'MODULO',
        'ASSIGN',
        'QM',
        'COLON',
        'BOOLT',
        'INTT',
        'REALT',
        'COMMA',
        'INTCASTOR',
        'INTARRCASTOR',
        'REALCASTOR',
        'BOOLCASTOR',
        'TOOBIG'
    )

    def __init__(self, lexer, types, hooks=None, **kwargs):
        # self.parser = yacc.yacc(module=self, **kwargs)
        self.types = defaultdict(lambda: 'int')
        self.types.update(types)
        self.function_hooks = hooks if hooks else dict()
        self.lexer = lexer
        self.errored = False
        self.context = dict()
        self.parser = yacc.yacc(module=self, **kwargs)

    def p_end(self, p):
        """end : expr
               | empty
        """
        if len(p) == 2:
            self.result = p[1] if not self.errored else False
            # print('p[1], self.errored',p[1], self.errored)
            # print('result:', self.result, 'errored: ', self.errored)
            self.errored = False

    def p_types(self, p):
        """inttype : INTT
           realtype : REALT
           booltype : BOOLT
        """
        if len(p) == 2:
            p[0] = p[1]

    def p_leftv_expr(self, p):
        """expr : leftv
        """
        p[0] = p[1]

    def p_define_new(self, p):
        """leftv : inttype  VARIABLE
                 | realtype VARIABLE
                 | booltype VARIABLE
                 | leftv DOT VARIABLE
                 | VARIABLE
        """
        if p.slice[1].type == 'inttype':
            p[0] = z3.Int(p[2])
            p.slice[0].name = p[2]
            name = p[2]
            self.types[name] = 'int'
        elif p.slice[1].type == 'realtype':
            p[0] = z3.Real(p[2])
            p.slice[0].name = p[2]
            name = p[2]
            self.types[name] = 'double'
        elif p.slice[1].type == 'booltype':
            p[0] = z3.Bool(p[2])
            p.slice[0].name = p[2]
            name = p[2]
            self.types[name] = 'bool'
        elif len(p) == 2:
            if p[1] in self.context:
                p[0] = self.context[p[1]]
                p.slice[0].name = p[1]
                name = p[1]
                # print('{} in context, get {}'.format(name, p[0]))
            else:
                if p[1] not in self.types:
                    print(
                        'Warning: Type of {} is undefined, using default type: int'.format(p[1]))
                p[0] = self.type_switch[self.types[p[1]]](p[1])
                p.slice[0].name = p[1]
                name = p[1]
        elif len(p) == 4:
            var_name = '{}.{}'.format(p[1], p[3])
            if var_name not in self.types:
                print(
                    'Warning: Type of {} is undefined, using default type: int'.format(var_name))
            p[0] = self.type_switch[self.types[var_name]](var_name)
            p.slice[0].name = var_name
            name = var_name

        if len(p) > 2:
            self.context[name] = p[0]

    def p_variable_value(self, p):
        """expr : STRINGS
                | REAL
                | CHAR
                | INT
        """
        p[0] = p[1]

    def p_assign(self, p):
        """expr : leftv ASSIGN expr
        """
        key = getattr(p.slice[1], 'name')
        self.context[key] = p[3]
        p[1] = p[3]
        p[0] = True

    def p_expression(self, p):
        """expr : expr LBRACK expr RBRACK
                | LPAREN expr RPAREN
        """
        if len(p) == 4:  # binary ops, paren, element access
            if p.slice[2].type == 'binary_op':
                p[0] = self.binary_ops[p[2]](p[1], p[3])
            elif p.slice[1].type == 'LPAREN':
                p[0] = p[2]
        elif len(p) == 5:  # array access
            p[0] = p[1][p[3]]

    def p_qsmark_choice(self, p):
        """expr : expr QM expr COLON expr
        """
        p[0] = z3.If(p[1], p[3], p[5])
        print(p[1], p[3], p[5])

    def p_binary_ops(self, p):
        """expr : expr GT expr
                | expr GTE expr
                | expr LT expr
                | expr LTE expr
                | expr EQ expr
                | expr NEQ expr
                | expr PLUS expr
                | expr TIME expr
                | expr MINUS expr
                | expr DIVIDE expr
                | expr MODULO expr
                | expr OR expr
                | expr AND expr
        """
        if len(p) == 4:
            # print(p[1], p[3], p[2])
            p[0] = self.binary_ops[p[2]](p[1], p[3])
            # print(p[0])
        elif len(p) == 2:
            p[0] = p[1]

    def p_unary_ops(self, p):
        """expr : MINUS expr
                | NOT expr
        """
        p[0] = self.unary_ops[p[1]](p[2])

    def p_casting(self, p):
        """expr : INTCASTOR expr
                | INTARRCASTOR expr
                | REALCASTOR expr
                | BOOLCASTOR expr
        """
        p[0] = self.unary_ops[p.slice[1].type](p[2])

    def p_function(self, p):
        """expr : leftv LPAREN paramList RPAREN
           paramList : paramList COMMA expr
                     | expr
        """
        if len(p) == 5:
            # TODO: Add `Math.Abs()` checker here!!!!

            if str(p[1]) not in self.function_hooks:
                print(
                    'Function {} not found, treating as plain string'.format(p[1]))
            p[0] = self.function_hooks[str(p[1])](*p[3])
        elif len(p) == 4:
            p[0] = p[1] + [p[3], ]
        elif len(p) == 2:
            p[0] = [p[1], ]

    # def p_casting(self, p):
    #   """castor : LPAREN inttype RPAREN
    #             | LPAREN realtype RPAREN
    #   """
    #   if p.slice[2].type == 'inttype':
    #     p[0] = '2int'
    #   elif p.slice[2].type == 'realtype':
    #     p[0] = '2real'

    def p_empty(self, p):
        """empty :
        """
        pass

    def p_error(self, p):
        print("Syntax error, treating as string: {}".format(p))
        self.errored = True
        raise ValueError('Syntax error')

    def test(self, data):
        # data = 'a != (int[])null&&a[2] + a[3] < 4&&-51 < a[0]&&a[0] < 51&&-51 < a[1]&&a[1] < 51&&-51 < a[2]&&a[2] < 51&&a.Length == 3&&a[1] >= a[0]&&a[0] >= a[1]&&a[2] >= a[0]&&a[0] >= a[2]&&a[0] + a[2] * a[1]&&int s = a[0] - a[2]&&s > a[2] - a[1]&&(a[2]!=1 || a[2]!=4)&&4u < (uint)(1 + a[4])&&a[5] == \'c\'&&Math.floor(a[0])&&a[2] < a[1] ? a[0] % a[1] : a[1] % a[0]&&double s0 = 0.98&&s1 = 0.6&&s1 + -(double)((int)s0) != 0.49'.split('&&')
        # data = 'a != (int[])null&&-51 < a[0]&&a[0] < 51&&1 < a.Length&&-51 < a[1]&&a[1] < 51&&a[1] < a[0]&&a.Length == 2&&a[0] >= a[1]'.split('&&')
        # data = data.replace('\\r\\n', '')
        # data = data.split('&&')
        models = []
        errors = []
        toAdd = False  # Don't add the preamble
        for d in data:
            if not d:
                continue
            # print(d)
            try:
                # print(d)
                ret = self.parse(d)
                # print(ret)

                if type(ret) == z3.z3.ArithRef:
                    ret = z3.If(ret == 0, True, False)
            except (ValueError, KeyError) as e:
                ret = None
            except z3.z3types.Z3Exception as e:
                ret = None
                print('Z3 error', e)

            # Changed 'ret == False' -> 'ret is False' to avoid triggering int 0
            if ret is False or ret == None:
                errors.append(d)
            else:
                models.append(ret)
        # self.parser.clear_context()
        # Checks if all eles in `models` eval to True
        retVal = '&&'.join(sorted(errors)), z3.simplify(
            reduce(z3.And, models, True)) if len(models) > 0 else z3.BoolVal(True)
        return retVal

    def test2(self, data: list):
        results = []
        for d in data:
            print(d)
            try:
                self.parser.parse(d, lexer=self.lexer)
            except (ValueError, KeyError) as e:
                self.result = None
            except z3.z3types.Z3Exception as e:
                self.result = None
                print('Z3 error', e)
            # except ImportError as e:
                # pass
            print(self.result)
            self.errored = False
            print('-----')
            results.append(self.result)
        return results

    def parse(self, text):
        self.parser.parse(text, lexer=self.lexer.clone())
        return self.result

    def predParse(self, pred):
        models = []
        errors = []
        try:
            ret = self.parse(pred)
            if type(ret) == z3.z3.ArithRef:
                ret = z3.If(ret == 0, True, False)
        except (ValueError, KeyError) as e:
            ret = None
        except z3.z3types.Z3Exception as e:
            ret = None
            print('Z3 error', e)

        # Changed 'ret == False' -> 'ret is False' to avoid triggering int 0
        if ret is False or ret == None:
            errors.append(pred)
        else:
            models.append(ret)
        # Checks if all eles in `models` eval to True
        retVal = '&&'.join(sorted(errors)), z3.simplify(
            reduce(z3.And, models, True)) if len(models) > 0 else z3.BoolVal(True)
        return retVal[1]

    def clear_context(self):
        self.context = dict()
Ejemplo n.º 10
0
    def cast(self, value, is_type, to_type):
        if is_type is Types.STRING and isinstance(to_type,
                                                  z3.z3.DatatypeSortRef):
            # the value is a string and it should be cast to a datatyperef
            # (i.e. an enum-type), just return the value because we can deal with it
            return value

        value_is_int = isinstance(value, int)
        value_is_float = isinstance(value, float)

        if is_type is to_type:  # already correct type, just return the value
            return value
            """ INT <---> INTEGER """
        elif is_type is Types.INT and to_type is Types.INTEGER:
            if value_is_int or value_is_float:
                return value  # this happens if it is an int numeral (e.g. 2)
            else:
                return z3.BV2Int(value)
        elif is_type is Types.INTEGER and to_type is Types.INT:
            if value_is_int or value_is_float:
                return value
            else:
                return z3.Int2BV(value, 32)
            """ INT <---> FLOAT """
        elif is_type is Types.FLOAT and to_type is Types.INT:
            if value_is_float:
                return value  # this happens if it is a float numeral (e.g. 3.14)
            else:
                return z3.fpToSBV(z3.RNE(), value, z3.BitVecSort(32))
        elif is_type is Types.INT and to_type is Types.FLOAT:
            if value_is_int:
                return value
            else:
                return z3.fpSignedToFP(z3.RNE(), value, z3.Float32())
            """ INTEGER <---> FLOAT """
        elif is_type is Types.FLOAT and to_type is Types.INTEGER:
            if value_is_float:
                return value  # this happens if it is a float numeral (e.g. 3.14)
            else:
                return self.cast(self.cast(value, Types.FLOAT, Types.INT),
                                 Types.INT, Types.INTEGER)
        elif is_type is Types.INTEGER and to_type is Types.FLOAT:
            if value_is_int:
                return value
            else:
                return self.cast(self.cast(value, Types.INTEGER, Types.INT),
                                 Types.INT, Types.FLOAT)
            """ from REAL """
        elif is_type is Types.REAL and to_type is Types.INTEGER:
            if value_is_float:
                return value
            else:
                return z3.ToInt(value)
        elif is_type is Types.REAL and to_type is Types.INT:
            return self.cast(self.cast(value, Types.REAL, Types.INTEGER),
                             Types.INTEGER, Types.INT)
        elif is_type is Types.REAL and to_type is Types.FLOAT:
            """
            Rounding modes: probably should make these parameterizable!
            roundNearestTiesToEven ... RNE() = default
            roundNearestTiesToAway ... RNA()
            roundTowardPositive ...... RTP()
            roundTowardNegative ...... RTN()
            roundTowardZero .......... RTZ()
            """
            if value_is_int or value_is_float:  # int numeral
                return value
            else:
                return z3.fpRealToFP(z3.RNE(), value, z3.Float32())
            """ to REAL """
        elif is_type is Types.INT and to_type is Types.REAL:
            if value_is_int or value_is_float:  # int numeral
                return value
            else:
                return z3.ToReal(self.cast(value, Types.INT, Types.INTEGER))
        elif is_type is Types.INTEGER and to_type is Types.REAL:
            if value_is_int or value_is_float:  # int numeral
                return value
            else:
                return z3.ToReal(value)
        elif is_type is Types.FLOAT and to_type is Types.REAL:
            if value_is_int or value_is_float:
                return value  # this happens if it is a float numeral (e.g. 3.14)
            else:
                return z3.fpToReal(value)
            """ FROM BOOL conversions """
        elif is_type is Types.BOOL and to_type is Types.INT:
            return z3.If(value, z3.BitVecVal(1, 32), z3.BitVecVal(0, 32))
        elif is_type is Types.BOOL and to_type is Types.INTEGER:
            return z3.If(value, 1, 0)
        elif is_type is Types.BOOL and to_type is Types.REAL:
            return z3.If(value, 1.0, 0.0)
        elif is_type is Types.BOOL and to_type is Types.FLOAT:
            return z3.If(value, z3.FPVal(1.0, z3.Float32()),
                         z3.FPVal(0.0, z3.Float32()))
            """ TO BOOL conversions """
        elif is_type is Types.INT and to_type is Types.BOOL:
            return value == 1
        elif is_type is Types.INTEGER and to_type is Types.BOOL:
            return value == 1
        elif is_type is Types.REAL and to_type is Types.BOOL:
            return value == 1
        elif is_type is Types.FLOAT and to_type is Types.BOOL:
            return value == 1

        raise TypeError(f"Don't know how to cast from {is_type} to {to_type}!")
Ejemplo n.º 11
0
 def walk_toreal(self, formula, args, **kwargs):
     return z3.ToReal(args[0])
Ejemplo n.º 12
0
 def cast(expr, type_):
     if type_ == float:
         return z3.ToReal(expr)
     else:
         raise NotImplementedError
Ejemplo n.º 13
0
 def as_z3(self):
     return z3.ToReal(self.expr.as_z3())
Ejemplo n.º 14
0
 def rec(t):
     if t.is_var():
         z3_t = convert_const(t.name, t.T, ctx)
         if t.T == NatType and t.name not in assms:
             assms[t.name] = z3_t >= 0
         return z3_t
     elif t.is_forall():
         nm = name.get_variant_name(t.arg.var_name, var_names)
         var_names.append(nm)
         v = Var(nm, t.arg.var_T)
         z3_v = convert_const(nm, t.arg.var_T, ctx)
         return z3.ForAll(z3_v, rec(t.arg.subst_bound(v)))
     elif t.is_exists():
         nm = name.get_variant_name(t.arg.var_name, var_names)
         var_names.append(nm)
         v = Var(nm, t.arg.var_T)
         z3_v = convert_const(nm, t.arg.var_T, ctx)
         return z3.Exists(z3_v, rec(t.arg.subst_bound(v)))
     elif t.is_number():
         return t.dest_number()
     elif t.is_implies():
         return z3.Implies(rec(t.arg1), rec(t.arg))
     elif t.is_equals():
         return rec(t.arg1) == rec(t.arg)
     elif t.is_conj():
         return z3.And(rec(t.arg1), rec(t.arg)) if ctx is None else z3.And(
             rec(t.arg1), rec(t.arg), ctx)
     elif t.is_disj():
         return z3.Or(rec(t.arg1), rec(t.arg)) if ctx is None else z3.Or(
             rec(t.arg1), rec(t.arg), ctx)
     elif logic.is_if(t):
         b, t1, t2 = t.args
         return z3.If(rec(b), rec(t1), rec(t2), ctx)
     elif t.is_not():
         return z3.Not(rec(t.arg), ctx)
     elif t.is_plus():
         return rec(t.arg1) + rec(t.arg)
     elif t.is_minus():
         m, n = rec(t.arg1), rec(t.arg)
         if t.arg1.get_type() == NatType:
             return z3.If(m >= n, m - n, 0, ctx)
         return m - n
     elif t.is_uminus():
         return -rec(t.arg)
     elif t.is_times():
         return rec(t.arg1) * rec(t.arg)
     elif t.is_less_eq():
         return rec(t.arg1) <= rec(t.arg)
     elif t.is_less():
         return rec(t.arg1) < rec(t.arg)
     elif t.is_greater_eq():
         return rec(t.arg1) >= rec(t.arg)
     elif t.is_greater():
         return rec(t.arg1) > rec(t.arg)
     elif t.is_divides():
         return rec(t.arg1) / rec(t.arg)
     elif t.is_comb('of_nat', 1):
         if t.get_type() == RealType:
             if t.arg.is_var():
                 if t.arg.name not in to_real:
                     nm = name.get_variant_name("r" + t.arg.name, var_names)
                     var_names.append(nm)
                     to_real[t.arg.name] = nm
                     z3_t = convert_const(nm, RealType, ctx)
                     assms[nm] = z3_t >= 0
                     return z3_t
                 else:
                     return convert_const(to_real[t.arg.name], RealType,
                                          ctx)
             return z3.ToReal(rec(t.arg))
         else:
             raise Z3Exception("convert: unsupported of_nat " + repr(t))
     elif t.is_comb('max', 2):
         a, b = rec(t.arg1), rec(t.arg)
         return z3.If(a >= b, a, b, ctx)
     elif t.is_comb('min', 2):
         a, b = rec(t.arg1), rec(t.arg)
         return z3.If(a <= b, a, b, ctx)
     elif t.is_comb('abs', 1):
         a = rec(t.arg)
         return z3.If(a >= 0, a, -a, ctx)
     elif t.is_comb('member', 2):
         a, S = rec(t.arg1), rec(t.arg)
         return S(a)
     elif t.is_comb():
         return rec(t.fun)(rec(t.arg))
     elif t.is_const():
         if t == true:
             return z3.BoolVal(True, ctx)
         elif t == false:
             return z3.BoolVal(False, ctx)
         else:
             raise Z3Exception("convert: unsupported constant " + repr(t))
     else:
         raise Z3Exception("convert: unsupported operation " + repr(t))
Ejemplo n.º 15
0
 def __k_float__(self):
     try:
         return inference.InferenceResult.load_result(
             Z3Proxy.init_expr(z3.ToReal(self.value), {**self.defaults}))
     except z3.Z3Exception:
         return inference.InferenceResult.load_result(nodes.Uninferable())
# Make sure they are 0 or 1
for x in X:
    S.add(x >= 0)
    S.add(x <= 1)

Y = []
Z = []
val = 0
# Use the lists from before to build up what the value of a solution would be
for x in X:
    y = z3.Real('y' + str(val))
    z = z3.Real('z' + str(val))
    Y.append(y)
    Z.append(z)
    S.add(y == z3.ToReal(x) * maximized_parameter_vector[val])
    S.add(z == z3.ToReal(x) * minimized_parameter_vector[val])
    val += 1

# Set up the min and max
S.maximize(z3.Sum(Y))
S.minimize(z3.Sum(Z))

# Get a solution
S.check()
solution = S.model()

print("Here are the zipcodes you may be interested in:")

val = 0
solution_zips = []