예제 #1
0
 def assume(self,
            condition,
            manager: PyManager = None,
            bwd: bool = False) -> 'Box2State':
     if self.is_bottom():
         return self
     if isinstance(condition, tuple):
         condition = list(condition)
     if isinstance(condition, list):
         for feature, (lower, upper) in condition:
             self.bounds[feature.name].meet(IntervalLattice(lower, upper))
         return self
     elif isinstance(condition, BinaryBooleanOperation):
         if condition.operator == BinaryBooleanOperation.Operator.Or:
             right = deepcopy(self).assume(condition.right, bwd=bwd)
             return self.assume(condition.left, bwd=bwd).join(right)
         elif condition.operator == BinaryBooleanOperation.Operator.And:
             assert isinstance(condition.left, BinaryComparisonOperation)
             assert isinstance(condition.right, BinaryComparisonOperation)
             assert isinstance(condition.left.left, Literal)
             assert condition.left.operator == BinaryComparisonOperation.Operator.LtE
             assert isinstance(condition.left.right, VariableIdentifier)
             assert isinstance(condition.right.left, VariableIdentifier)
             assert condition.right.operator == BinaryComparisonOperation.Operator.LtE
             assert isinstance(condition.right.right, Literal)
             lower = eval(condition.left.left.val)
             upper = eval(condition.right.right.val)
             assert condition.left.right.name == condition.right.left.name
             self.bounds[condition.left.right.name].meet(
                 IntervalLattice(lower, upper))
             return self
     elif isinstance(condition, BinaryComparisonOperation):
         if condition.operator == BinaryComparisonOperation.Operator.Gt:
             assert isinstance(condition.left, VariableIdentifier)
             assert isinstance(condition.right, Literal)
             lower = eval(condition.right.val)
             upper = 1
             self.bounds[condition.left.name].meet(
                 IntervalLattice(lower, upper))
             return self
         elif condition.operator == BinaryComparisonOperation.Operator.LtE:
             assert isinstance(condition.left, VariableIdentifier)
             assert isinstance(condition.right, Literal)
             lower = 0
             upper = eval(condition.right.val)
             self.bounds[condition.left.name].meet(
                 IntervalLattice(lower, upper))
             return self
     # elif isinstance(condition, PyTcons1):
     #     abstract1 = self.domain(manager, self.environment, array=PyTcons1Array([condition]))
     #     self.state = self.state.meet(abstract1)
     #     return self
     elif isinstance(condition, set):
         assert len(condition) == 1
         self.assume(condition.pop(), bwd=bwd)
         return self
     raise NotImplementedError(
         f"Assumption of {condition.__class__.__name__} is unsupported!")
예제 #2
0
    def __init__(self, inputs: Set[VariableIdentifier], precursory: State = None):
        super().__init__(precursory=precursory)
        self.inputs = {input.name for input in inputs}

        # PRE: all the inputs in [0, 1]
        self.bounds = {input: (IntervalLattice(0, 0), IntervalLattice(1, 1))
                       for input in self.inputs}

        # the free coeff is indicated by '_' in the dictionary self.poly
        self.poly = {input: ({'_': 0.0}, {'_': 1.0}) for input in self.inputs}

        self.flag = None
예제 #3
0
 def affine(self, left: List[PyVar], right: List[PyTexpr1]) -> 'NeurifyState':
     if self.is_bottom():
         return self
     for lhs, expr in zip(left, right):
         name = str(lhs)
         rhs = texpr_to_dict(expr)
         _inf, inf = deepcopy(rhs), deepcopy(rhs)
         _sup, sup = deepcopy(rhs), deepcopy(rhs)
         self.poly[name] = (_inf, _sup)
         # while there is a non-input-variable in inf
         while any(variable in inf and variable not in self.inputs for variable in self.poly):
             for variable in self.poly:
                 if variable in inf and variable not in self.inputs:  # should be replaced
                     coeff = inf[variable]
                     if coeff > 0:
                         replacement = self.poly[variable][LOW]
                     elif coeff < 0:
                         replacement = self.poly[variable][UP]
                     else:  # coeff == 0
                         replacement = dict()
                         replacement['_'] = 0.0
                     del inf[variable]
                     for var, val in replacement.items():
                         if var in inf:
                             inf[var] += coeff * val
                         else:
                             inf[var] = coeff * val
         # while there is a non-input-variable in sup
         while any(variable in sup and variable not in self.inputs for variable in self.poly):
             for variable in self.poly:
                 if variable in sup and variable not in self.inputs:  # should be replaced
                     coeff = sup[variable]
                     if coeff > 0:
                         replacement = self.poly[variable][UP]
                     elif coeff < 0:
                         replacement = self.poly[variable][LOW]
                     else:  # coeff == 0
                         replacement = dict()
                         replacement['_'] = 0.0
                     del sup[variable]
                     for var, val in replacement.items():
                         if var in sup:
                             sup[var] += coeff * val
                         else:
                             sup[var] = coeff * val
         ext_bounds = {k: IntervalLattice(l.lower, u.upper) for k, (l, u) in self.bounds.items()}
         lower = evaluate(inf, ext_bounds)
         upper = evaluate(sup, ext_bounds)
         self.bounds[name] = (IntervalLattice(lower.lower, lower.upper),
                              IntervalLattice(upper.lower, upper.upper))
     return self
예제 #4
0
    def resize_bounds(self, var_name, new_bounds):
        new_low_lower = new_bounds.lower
        new_low_upper = self.bounds[var_name][LOW].upper
        new_up_lower = self.bounds[var_name][UP].lower
        new_up_upper = new_bounds.upper

        if new_low_lower > new_low_upper:
            new_low_upper = new_low_lower
        if new_up_upper < new_up_lower:
            new_up_lower = new_up_upper

        self.bounds[var_name] = (
            IntervalLattice(new_low_lower, new_low_upper),
            IntervalLattice(new_up_lower, new_up_upper)
            )
예제 #5
0
    def relu(self,
             stmt: PyVar,
             active: bool = False,
             inactive: bool = False) -> 'Symbolic3State':
        if self.is_bottom():
            return self
        self.flag = None

        name = str(stmt)
        lattice: IntervalLattice = self.bounds[name]
        lower, upper = lattice.lower, lattice.upper
        if upper <= 0 or inactive:
            zero = dict()
            zero['_'] = 0.0
            self.symbols[name] = (name, zero)
            self.bounds[name] = IntervalLattice(0, 0)
            self.flag = -1
        elif 0 <= lower or active:
            if active and lower < 0:
                bounds = self.bounds[name]
                self.bounds[name] = bounds.meet(IntervalLattice(0, upper))
                del self.symbols[name]
            self.flag = 1
        else:
            _active, _inactive = deepcopy(self.bounds), deepcopy(self.bounds)
            _active[name] = _active[name].meet(IntervalLattice(0, upper))
            _inactive[name] = _inactive[name].meet(IntervalLattice(0, 0))

            if any(element.is_bottom() for element in _active.values()):
                zero = dict()
                zero['_'] = 0.0
                self.symbols[name] = (name, zero)
                self.flag = -1
            elif any(element.is_bottom() for element in _inactive.values()):
                self.flag = 1
            else:
                del self.symbols[name]
                self.flag = None

            join = dict()
            for variable, itv in _active.items():
                join[variable] = itv.join(_inactive[variable])
            self.bounds[name] = join[name].meet(IntervalLattice(0, upper))
            self.flag = None

        return self
예제 #6
0
 def __init__(self,
              inputs: Set[VariableIdentifier],
              precursory: State = None):
     super().__init__(precursory=precursory)
     self.inputs = {input.name for input in inputs}
     self.bounds = dict()
     for input in self.inputs:
         self.bounds[input] = IntervalLattice(0, 1)
     self.flag = None
예제 #7
0
def evaluate(dictionary, bounds):
    result = IntervalLattice(0, 0)
    for var, val in dictionary.items():
        coeff = IntervalLattice(val, val)
        if var != '_':
            result = result._add(coeff._mult(bounds[var]))
        else:
            result = result._add(coeff)
    return result
예제 #8
0
    def affine(self, left: List[PyVar], right: List[PyTexpr1]) -> 'Box2State':
        if self.is_bottom():
            return self
        for lhs, expr in zip(left, right):
            name = str(lhs)
            rhs = texpr_to_dict(expr)
            inf = deepcopy(rhs)
            sup = deepcopy(rhs)

            lower = evaluate(inf, self.bounds)
            upper = evaluate(sup, self.bounds)
            self.bounds[name] = IntervalLattice(lower.lower, upper.upper)
        return self
예제 #9
0
    def _meet(self, other: 'NeurifyState') -> 'NeurifyState':
        for var in self.bounds:
            other_bound = IntervalLattice(other.bounds[var][LOW].lower, other.bounds[var][UP].upper)
            self_bound = IntervalLattice(self.bounds[var][LOW].lower, self.bounds[var][UP].upper)
            self_bound.meet(other_bound)
            self.bounds[var] = (
                IntervalLattice(self_bound.lower, self_bound.lower),
                IntervalLattice(self_bound.upper, self_bound.upper))

            self.poly[var] = (
                {'_': self.bounds[var][LOW].lower},
                {'_': self.bounds[var][UP].upper})
        return self
예제 #10
0
    def relu(self,
             stmt: PyVar,
             active: bool = False,
             inactive: bool = False) -> 'Box2State':
        if self.is_bottom():
            return self
        name = str(stmt)
        lattice: IntervalLattice = self.bounds[name]
        lower, upper = lattice.lower, lattice.upper
        if upper <= 0 or inactive:
            # l_j = u_j = 0
            self.bounds[name] = IntervalLattice(0, 0)
            # 0 <= x_j <= 0
            self.flag = -1
        elif 0 <= lower or active:
            if active and lower < 0:
                self.bounds[name] = IntervalLattice(0, upper)
            self.flag = 1
        else:  # case (c) in Fig. 4, equation (4)
            _active, _inactive = deepcopy(self.bounds), deepcopy(self.bounds)
            _active[name] = _active[name].meet(IntervalLattice(0, upper))
            _inactive[name] = _inactive[name].meet(IntervalLattice(0, 0))

            if any(element.is_bottom() for element in _active.values()):
                self.flag = -1
            elif any(element.is_bottom() for element in _inactive.values()):
                self.flag = 1
            else:
                self.flag = None

            join = dict()
            for variable, itv in _active.items():
                join[variable] = itv.join(_inactive[variable])
            self.bounds[name] = join[name].meet(IntervalLattice(0, upper))
            self.flag = None
        return self
예제 #11
0
 def affine(self, left: List[PyVar],
            right: List[PyTexpr1]) -> 'Symbolic3State':
     if self.is_bottom():
         return self
     assignments = dict()
     for lhs, expr in zip(left, right):
         name = str(lhs)
         rhs = texpr_to_dict(expr)
         for sym, val in self.symbols.values():
             rhs = substitute_in_dict(rhs, sym, val)
         assignments[name] = (name, rhs)
         bound = evaluate(rhs, self.bounds)
         self.bounds[name] = IntervalLattice(bound.lower, bound.upper)
     self.symbols = assignments
     return self
예제 #12
0
    def relu(self, stmt: PyVar, active: bool = False, inactive: bool = False) -> 'NeurifyState':
        if self.is_bottom():
            return self
        name = str(stmt)
        low_lattice, up_lattice = self.bounds[name]
        low_lower, low_upper = low_lattice.lower, low_lattice.upper
        up_lower, up_upper = up_lattice.lower, up_lattice.upper
        self.set_flag(low_lower, up_upper, active, inactive)
        if low_upper <= 0 or inactive:
            self.bounds[name] = (IntervalLattice(0, 0), self.bounds[name][UP])
            self.poly[name] = ({'_': 0.0}, self.poly[name][UP])
        elif 0 <= low_lower or active:
            if active and low_lower < 0:
                self.bounds[name] = (IntervalLattice(0, low_upper), self.bounds[name][UP])
                self.poly[name] = ({'_': 0.0}, self.poly[name][UP])
        else:
            m = low_upper / (low_upper - low_lower)
            sup = self.poly[name][LOW] # sup does side effects over self.poly[name][UP]
            for var, val in sup.items():
                sup[var] = m * val
            self.bounds[name] = (IntervalLattice(low_lower*m, low_upper*m), self.bounds[name][UP])

        if up_upper <= 0 or inactive:
            self.bounds[name] = (self.bounds[name][LOW], IntervalLattice(0, 0))
            self.poly[name] = (self.poly[name][LOW], {'_': 0.0})
        elif 0 <= up_lower or active:
            if active and up_lower < 0:
                self.bounds[name] = (self.bounds[name][LOW], IntervalLattice(0, up_upper))
        else:
            m = up_upper / (up_upper - up_lower)
            q = up_upper * (-up_lower) / (up_upper - up_lower)
            sup = self.poly[name][UP] # sup does side effects over self.poly[name][UP]
            for var, val in sup.items():
                sup[var] = m * val
            sup['_'] += q
            self.bounds[name] = (self.bounds[name][LOW], IntervalLattice(up_lower*m+q, up_upper*m+q))
        return self
예제 #13
0
 def resize_bounds(self, var_name, new_bounds):
     self.bounds[var_name] = IntervalLattice(new_bounds.lower,
                                             new_bounds.upper)
예제 #14
0
 def get_bounds(self, var_name):
     low, up = self.bounds[var_name]
     return IntervalLattice(low.lower, up.upper)
예제 #15
0
 def __assume_helper(self, feature, lower, upper):
     self.bounds[feature.name] = (IntervalLattice(lower, lower), IntervalLattice(upper, upper))
     self.poly[feature.name] = (
         {'_': self.bounds[feature.name][LOW].lower},
         {'_': self.bounds[feature.name][UP].upper}
     )