def restriction(cls, self, parameters, variable, restricted_domain): """ Restrict the domain INPUT: - ``restricted_domain`` -- a :class:`~sage.sets.real_set.RealSet` or something that defines one. OUTPUT: A new piecewise function obtained by restricting the domain. EXAMPLES:: sage: f = piecewise([((-oo, oo), x)]); f piecewise(x|-->x on (-oo, +oo); x) sage: f.restriction([[-1,1], [3,3]]) piecewise(x|-->x on [-1, 1] + {3}; x) """ restricted_domain = RealSet(*restricted_domain) new_param = [] for domain, func in parameters: domain = domain.intersection(restricted_domain) new_param.append((domain, func)) return piecewise(new_param, var=variable)
def domain(cls, self, parameters, variable): """ Return the domain OUTPUT: The union of the domains of the individual pieces as a :class:`~sage.sets.real_set.RealSet`. EXAMPLES:: sage: f = piecewise([([0,0], sin(x)), ((0,2), cos(x))]); f piecewise(x|-->sin(x) on {0}, x|-->cos(x) on (0, 2); x) sage: f.domain() [0, 2) """ intervals = [] for domain, func in parameters: intervals += list(domain) return RealSet(*intervals)
def __call__(self, function_pieces, **kwds): r""" Piecewise functions INPUT: - ``function_pieces`` -- a list of pairs consisting of a domain and a symbolic function. - ``var=x`` -- a symbolic variable or ``None`` (default). The real variable in which the function is piecewise in. OUTPUT: A piecewise-defined function. A ``ValueError`` will be raised if the domains of the pieces are not pairwise disjoint. EXAMPLES:: sage: my_abs = piecewise([((-1, 0), -x), ([0, 1], x)], var=x); my_abs piecewise(x|-->-x on (-1, 0), x|-->x on [0, 1]; x) sage: [ my_abs(i/5) for i in range(-4, 5)] [4/5, 3/5, 2/5, 1/5, 0, 1/5, 2/5, 3/5, 4/5] TESTS:: sage: piecewise([([-1, 0], -x), ([0, 1], x)], var=x) Traceback (most recent call last): ... ValueError: domains must be pairwise disjoint sage: step = piecewise([((-1, 0), -1), ([0, 0], 0), ((0, 1), 1)], var=x); step piecewise(x|-->-1 on (-1, 0), x|-->0 on {0}, x|-->1 on (0, 1); x) sage: step(-1/2), step(0), step(1/2) (-1, 0, 1) """ from types import FunctionType var = kwds.pop('var', None) parameters = [] domain_list = [] for piece in function_pieces: domain, function = piece if not isinstance(domain, RealSet): domain = RealSet(domain) if domain.is_empty(): continue if isinstance(function, FunctionType): if var is None: var = SR.var('x') if function.func_code.co_argcount == 0: function = function() else: function = function(var) function = SR(function) if var is None and len(function.variables()) > 0: var = function.variables()[0] parameters.append((domain, function)) domain_list.append(domain) if not RealSet.are_pairwise_disjoint(*domain_list): raise ValueError('domains must be pairwise disjoint') if var is None: var = self.default_variable() parameters = SR._force_pyobject(tuple(parameters), recursive=False) return BuiltinFunction.__call__(self, parameters, var, **kwds)
def piecewise_add(cls, self, parameters, variable, other): """ Return a new piecewise function with domain the union of the original domains and functions summed. Undefined intervals in the union domain get function value `0`. EXAMPLES:: sage: f = piecewise([([0,1], 1), ((2,3), x)]) sage: g = piecewise([((1/2, 2), x)]) sage: f.piecewise_add(g).unextend_zero() piecewise(x|-->1 on (0, 1/2], x|-->x + 1 on (1/2, 1], x|-->x on (1, 2) + (2, 3); x) """ points = ([minus_infinity] + sorted(set(self.end_points() + other.end_points())) + [infinity]) domain = [] funcs = [] contains_lower = False contains_upper = False for i in range(len(points)-1): try: contains_lower = (self.domain().contains(points[i]) or other.domain().contains(points[i])) and not contains_upper contains_upper = (self.domain().contains(points[i+1]) or other.domain().contains(points[i+1])) if contains_lower: if contains_upper: rs = RealSet.closed(points[i],points[i+1]) else: rs = RealSet.closed_open(points[i],points[i+1]) else: if contains_upper: rs = RealSet.open_closed(points[i],points[i+1]) else: rs = RealSet.open(points[i],points[i+1]) point = (points[i+1] + points[i])/2 except ValueError: if points[i] == minus_infinity and points[i+1] == infinity: rs = RealSet.open(minus_infinity, infinity) point = 0 elif points[i] == minus_infinity: if contains_lower: rs = RealSet.unbounded_below_closed(points[i+1]) else: rs = RealSet.unbounded_below_open(points[i+1]) point = points[i+1]-1 elif points[i+1] == infinity: if contains_upper: rs = RealSet.unbounded_above_closed(points[i]) else: rs = RealSet.unbounded_above_open(points[i]) point = points[i]+1 else: raise try: ex1 = self.expression_at(point) except ValueError: ex1 = 0 try: ex2 = other.expression_at(point) except ValueError: ex2 = 0 ex = ex1 + ex2 if i>0 and funcs[-1] == ex: # extend the previous domain rs += domain[-1] domain[-1] = rs else: domain += rs funcs.append(ex) return piecewise(zip(domain, funcs))
from sage.sets.real_set import RealSet from sage.structure.element import Matrix as MatrixClass from sage.structure.factorization_integer import IntegerFactorization from sage.symbolic.expression import Expression from sage.symbolic.relation import solve from sage.symbolic.ring import SR pair_keep = staticmethod(lambda i, j: (i, j)) pair_swap = staticmethod(lambda i, j: (j, i)) CHECK_LEVELS = 4 INTERVAL = { (True, True): RealSet.closed, (True, False): RealSet.closed_open, (True, None): lambda l, u: RealSet.unbounded_above_closed(l), (False, True): RealSet.open_closed, (False, False): RealSet.open, (False, None): lambda l, u: RealSet.unbounded_above_open(l), (None, True): lambda l, u: RealSet.unbounded_below_closed(u), (None, False): lambda l, u: RealSet.unbounded_below_open(u), (None, None): lambda l, u: RealSet().complement() } def checklist(checks, inherit=None): """ Initialize the list of feasibility checking functions and return a decorator for the functions. """ if inherit is None:
def piecewise_add(cls, self, parameters, variable, other): """ Return a new piecewise function with domain the union of the original domains and functions summed. Undefined intervals in the union domain get function value `0`. EXAMPLES:: sage: f = piecewise([([0,1], 1), ((2,3), x)]) sage: g = piecewise([((1/2, 2), x)]) sage: f.piecewise_add(g).unextend_zero() piecewise(x|-->1 on (0, 1/2], x|-->x + 1 on (1/2, 1], x|-->x on (1, 2) + (2, 3); x) """ points = ([minus_infinity] + sorted(set(self.end_points() + other.end_points())) + [infinity]) domain = [] funcs = [] contains_lower = False contains_upper = False for i in range(len(points) - 1): try: contains_lower = (self.domain().contains(points[i]) or other.domain().contains( points[i])) and not contains_upper contains_upper = (self.domain().contains(points[i + 1]) or other.domain().contains(points[i + 1])) if contains_lower: if contains_upper: rs = RealSet.closed(points[i], points[i + 1]) else: rs = RealSet.closed_open(points[i], points[i + 1]) else: if contains_upper: rs = RealSet.open_closed(points[i], points[i + 1]) else: rs = RealSet.open(points[i], points[i + 1]) point = (points[i + 1] + points[i]) / 2 except ValueError: if points[i] == minus_infinity and points[i + 1] == infinity: rs = RealSet.open(minus_infinity, infinity) point = 0 elif points[i] == minus_infinity: if contains_lower: rs = RealSet.unbounded_below_closed(points[i + 1]) else: rs = RealSet.unbounded_below_open(points[i + 1]) point = points[i + 1] - 1 elif points[i + 1] == infinity: if contains_upper: rs = RealSet.unbounded_above_closed(points[i]) else: rs = RealSet.unbounded_above_open(points[i]) point = points[i] + 1 else: raise try: ex1 = self.expression_at(point) except ValueError: ex1 = 0 try: ex2 = other.expression_at(point) except ValueError: ex2 = 0 ex = ex1 + ex2 if i > 0 and funcs[-1] == ex: # extend the previous domain rs += domain[-1] domain[-1] = rs else: domain += rs funcs.append(ex) return piecewise(zip(domain, funcs))