def value(self, add): for term in add.args: if term.is_number or term in self.bounds or len( term.free_symbols) != 1: continue fs, = term.free_symbols if fs not in self.bounds: continue intrvl = Interval(*self.bounds[fs]) if is_increasing(term, intrvl, fs): self.bounds[term] = (term.subs({fs: self.bounds[fs][0]}), term.subs({fs: self.bounds[fs][1]})) elif is_decreasing(term, intrvl, fs): self.bounds[term] = (term.subs({fs: self.bounds[fs][1]}), term.subs({fs: self.bounds[fs][0]})) else: return add if all(term.is_number or term in self.bounds for term in add.args): bounds = [(term, term) if term.is_number else self.bounds[term] for term in add.args] largest_abs_guarantee = 0 for lo, hi in bounds: if lo <= 0 <= hi: continue largest_abs_guarantee = max(largest_abs_guarantee, min(abs(lo), abs(hi))) new_terms = [] for term, (lo, hi) in zip(add.args, bounds): if max(abs(lo), abs(hi)) >= largest_abs_guarantee * self.reltol: new_terms.append(term) return add.func(*new_terms) else: return add
def test_is_increasing(): assert is_increasing(x**3 - 3*x**2 + 4*x, S.Reals) assert is_increasing(-x**2, Interval(-oo, 0)) assert is_increasing(-x**2, Interval(0, oo)) is False assert is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) is False assert is_increasing(x**2 + y, Interval(1, oo), x) is True assert is_increasing(-x**2*a, Interval(1, oo), x) is True assert is_increasing(1) is True
def test_is_increasing(): """Test whether is_increasing returns correct value.""" a = Symbol('a', negative=True) assert is_increasing(x**3 - 3*x**2 + 4*x, S.Reals) assert is_increasing(-x**2, Interval(-oo, 0)) assert not is_increasing(-x**2, Interval(0, oo)) assert not is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) assert is_increasing(x**2 + y, Interval(1, oo), x) assert is_increasing(-x**2*a, Interval(1, oo), x) assert is_increasing(1) assert is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) is False
def test_is_increasing(): """Test whether is_increasing returns correct value.""" a = Symbol('a', negative=True) assert is_increasing(x**3 - 3*x**2 + 4*x, S.Reals) assert is_increasing(-x**2, Interval(-oo, 0)) assert not is_increasing(-x**2, Interval(0, oo)) assert not is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) assert is_increasing(x**2 + y, Interval(1, oo), x) assert is_increasing(-x**2*a, Interval(1, oo), x) assert is_increasing(1)
def value(self, add): for term in add.args: if term.is_number or term in self.bounds or len(term.free_symbols) != 1: continue fs, = term.free_symbols if fs not in self.bounds: continue intrvl = Interval(*self.bounds[fs]) if is_increasing(term, intrvl, fs): self.bounds[term] = ( term.subs({fs: self.bounds[fs][0]}), term.subs({fs: self.bounds[fs][1]}) ) elif is_decreasing(term, intrvl, fs): self.bounds[term] = ( term.subs({fs: self.bounds[fs][1]}), term.subs({fs: self.bounds[fs][0]}) ) else: return add if all(term.is_number or term in self.bounds for term in add.args): bounds = [(term, term) if term.is_number else self.bounds[term] for term in add.args] largest_abs_guarantee = 0 for lo, hi in bounds: if lo <= 0 <= hi: continue largest_abs_guarantee = max(largest_abs_guarantee, min(abs(lo), abs(hi))) new_terms = [] for term, (lo, hi) in zip(add.args, bounds): if max(abs(lo), abs(hi)) >= largest_abs_guarantee*self.reltol: new_terms.append(term) return add.func(*new_terms) else: return add
def test_issue_23401(): x = Symbol('x') expr = (x + 1) / (-1.0e-3 * x**2 + 0.1 * x + 0.1) assert is_increasing(expr, Interval(1, 2), x)
def check_constraints(model, constraints, intervals, characteristic_vals=None, verbose=0): """WIP function for Tc project. UseS Sympy to check for singularities and other limits.""" intervals = dict(intervals) feature_set = list(constraints.keys()) if characteristic_vals is None: characteristic_vals = { feature: i / 10 for i, feature in enumerate(feature_set) } for feature in feature_set: if feature not in intervals.keys(): intervals[feature] = sympy.Reals continue interval_min, interval_max = intervals[feature] if interval_min == "-oo" or interval_min == -np.inf: interval_min = -oo elif interval_max == "oo" or interval_max == np.inf: interval_max = oo interval = Interval(interval_min, interval_max) intervals[feature] = interval symbol_dict = { k: v for k, v in zip( feature_set, sympy.symbols( feature_set, positive=True, finite=True, infinite=False)) } expr = parse_expr(model.replace('^', '**'), local_dict=symbol_dict) passed = True checks = {k: {} for k in constraints.keys()} for feature, symbol in symbol_dict.items(): symbol_set = list(symbol_dict.values()) variable = symbol_set.pop(symbol_set.index(symbol)) interval = intervals[feature] univariate_expr = expr.subs([(symbol, characteristic_vals[str(symbol)]) for symbol in symbol_set]) if verbose > 1: print(univariate_expr) if constraints[feature].get('increasing', None) is not None: try: increasing = is_increasing(univariate_expr, interval=interval) except TypeError: increasing = False if increasing is None: # bug? increasing = False checks[feature]['increasing'] = increasing if increasing != constraints[feature]['increasing']: passed = False if constraints[feature].get('decreasing', None) is not None: try: decreasing = is_decreasing(univariate_expr, interval=interval) except TypeError: decreasing = False if decreasing is None: # bug? decreasing = False checks[feature]['decreasing'] = decreasing if decreasing != constraints[feature]['decreasing']: passed = False if constraints[feature].get('monotonic', None) is not None: try: monotonic = is_monotonic(univariate_expr, interval=interval) except TypeError: monotonic = False checks[feature]['monotonic'] = monotonic if monotonic != constraints[feature]['monotonic']: passed = False if constraints[feature].get('singularities', None) is not None: try: singularity_set = singularities(expr, variable, domain=interval) except TypeError: singularity_set = sympy.EmptySet checks[feature]['singularities'] = singularity_set # has_singularities = singularity_set is not sympy.EmptySet if singularity_set != constraints[feature]['singularities']: passed = False if constraints[feature].get('zero limit', None) is not None: try: zero_limit = sympy.limit(expr, variable, 0) except TypeError: zero_limit = None checks[feature]['zero limit'] = zero_limit if zero_limit != constraints[feature]['zero limit']: passed = False if verbose == 0: return passed else: return checks, passed