def adapt_to_callable(f, nargs=None): """ Tries to make every function in f into a (fast) callable function, returning a new list of functions and the expected arguments. INPUT: - ``f`` -- a list of functions; these can be symbolic expressions, polynomials, etc - ``nargs`` -- number of input args to have in the output functions OUTPUT: functions, expected arguments """ from sage.misc.misc import deprecation deprecation( "adapt_to_callable is a deprecated function. Please use functions from sage.misc.plot instead." ) try: from sage.symbolic.callable import is_CallableSymbolicExpression if sum([is_CallableSymbolicExpression(z) for z in f]): # Sum to get common universe; this works since f is # callable, and summing gets the arguments in the right # order. vars = sum(f).args() else: # Otherwise any free variable names in any order try: vars = tuple(sorted(set(sum([z.variables() for z in f], ())))) if len(vars) > 1: from sage.misc.misc import deprecation deprecation( "Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)" ) except AttributeError: vars = () f = [fast_float_constant(x) for x in f] except TypeError: vars = () f = [fast_float_constant(x) for x in f] if nargs is not None and len(vars) != nargs: vars = (vars + ('_', ) * nargs)[:nargs] return fast_float(f, *vars), vars
def adapt_to_callable(f, nargs=None): """ Tries to make every function in f into a (fast) callable function, returning a new list of functions and the expected arguments. INPUT: - ``f`` -- a list of functions; these can be symbolic expressions, polynomials, etc - ``nargs`` -- number of input args to have in the output functions OUTPUT: functions, expected arguments """ from sage.misc.misc import deprecation deprecation("adapt_to_callable is a deprecated function. Please use functions from sage.misc.plot instead.") try: from sage.symbolic.callable import is_CallableSymbolicExpression if sum([is_CallableSymbolicExpression(z) for z in f]): # Sum to get common universe; this works since f is # callable, and summing gets the arguments in the right # order. vars = sum(f).args() else: # Otherwise any free variable names in any order try: vars = tuple(sorted(set(sum( [z.variables() for z in f], ()) ))) if len(vars) > 1: from sage.misc.misc import deprecation deprecation("Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)") except AttributeError: vars = () f = [fast_float_constant(x) for x in f] except TypeError: vars = () f = [fast_float_constant(x) for x in f] if nargs is not None and len(vars) != nargs: vars = (vars + ('_',)*nargs)[:nargs] return fast_float(f, *vars), vars
def setup_for_eval_on_grid(funcs, ranges, plot_points=None, return_vars=False): """ Calculate the necessary parameters to construct a list of points, and make the functions fast_callable. INPUT: - ``funcs`` -- a function, or a list, tuple, or vector of functions - ``ranges`` -- a list of ranges. A range can be a 2-tuple of numbers specifying the minimum and maximum, or a 3-tuple giving the variable explicitly. - ``plot_points`` -- a tuple of integers specifying the number of plot points for each range. If a single number is specified, it will be the value for all ranges. This defaults to 2. - ``return_vars`` -- (default ``False``) If ``True``, return the variables, in order. OUTPUT: - ``fast_funcs`` - if only one function passed, then a fast callable function. If funcs is a list or tuple, then a tuple of fast callable functions is returned. - ``range_specs`` - a list of range_specs: for each range, a tuple is returned of the form (range_min, range_max, range_step) such that ``srange(range_min, range_max, range_step, include_endpoint=True)`` gives the correct points for evaluation. EXAMPLES:: sage: x,y,z=var('x,y,z') sage: f(x,y)=x+y-z sage: g(x,y)=x+y sage: h(y)=-y sage: sage.plot.misc.setup_for_eval_on_grid(f, [(0, 2),(1,3),(-4,1)], plot_points=5) (<sage.ext...>, [(0.0, 2.0, 0.5), (1.0, 3.0, 0.5), (-4.0, 1.0, 1.25)]) sage: sage.plot.misc.setup_for_eval_on_grid([g,h], [(0, 2),(-1,1)], plot_points=5) ((<sage.ext...>, <sage.ext...>), [(0.0, 2.0, 0.5), (-1.0, 1.0, 0.5)]) sage: sage.plot.misc.setup_for_eval_on_grid([sin,cos], [(-1,1)], plot_points=9) ((<sage.ext...>, <sage.ext...>), [(-1.0, 1.0, 0.25)]) sage: sage.plot.misc.setup_for_eval_on_grid([lambda x: x^2,cos], [(-1,1)], plot_points=9) ((<function <lambda> ...>, <sage.ext...>), [(-1.0, 1.0, 0.25)]) sage: sage.plot.misc.setup_for_eval_on_grid([x+y], [(x,-1,1),(y,-2,2)]) ((<sage.ext...>,), [(-1.0, 1.0, 2.0), (-2.0, 2.0, 4.0)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,-1,1),(y,-1,1)], plot_points=[4,9]) (<sage.ext...>, [(-1.0, 1.0, 0.6666666666666666), (-1.0, 1.0, 0.25)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,-1,1),(y,-1,1)], plot_points=[4,9,10]) Traceback (most recent call last): ... ValueError: plot_points must be either an integer or a list of integers, one for each range sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(1,-1),(y,-1,1)], plot_points=[4,9,10]) Traceback (most recent call last): ... ValueError: Some variable ranges specify variables while others do not sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(1,-1),(-1,1)], plot_points=5) doctest:...: DeprecationWarning: Unnamed ranges for more than one variable is deprecated and will be removed from a future release of Sage; you can used named ranges instead, like (x,0,2) See http://trac.sagemath.org/7008 for details. (<sage.ext...>, [(1.0, -1.0, 0.5), (-1.0, 1.0, 0.5)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], plot_points=5) (<sage.ext...>, [(1.0, -1.0, 0.5), (-1.0, 1.0, 0.5)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(x,-1,1)], plot_points=5) Traceback (most recent call last): ... ValueError: range variables should be distinct, but there are duplicates sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,1),(y,-1,1)]) Traceback (most recent call last): ... ValueError: plot start point and end point must be different sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(y,-1,1)], return_vars=True) (<sage.ext...>, [(1.0, -1.0, 2.0), (-1.0, 1.0, 2.0)], [x, y]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], return_vars=True) (<sage.ext...>, [(1.0, -1.0, 2.0), (-1.0, 1.0, 2.0)], [y, x]) """ if max(map(len, ranges)) != min(map(len, ranges)): raise ValueError( "Some variable ranges specify variables while others do not") if len(ranges[0]) == 3: vars = [r[0] for r in ranges] ranges = [r[1:] for r in ranges] if len(set(vars)) < len(vars): raise ValueError( "range variables should be distinct, but there are duplicates") else: vars, free_vars = unify_arguments(funcs) if len(free_vars) > 1: from sage.misc.superseded import deprecation deprecation( 7008, "Unnamed ranges for more than one variable is deprecated and will be removed from a future release of Sage; you can used named ranges instead, like (x,0,2)" ) # pad the variables if we don't have enough nargs = len(ranges) if len(vars) < nargs: vars += ('_', ) * (nargs - len(vars)) ranges = [[float(z) for z in r] for r in ranges] if plot_points is None: plot_points = 2 if not isinstance(plot_points, (list, tuple)): plot_points = [plot_points] * len(ranges) elif len(plot_points) != nargs: raise ValueError( "plot_points must be either an integer or a list of integers, one for each range" ) plot_points = [int(p) if p >= 2 else 2 for p in plot_points] range_steps = [ abs(range[1] - range[0]) / (p - 1) for range, p in zip(ranges, plot_points) ] if min(range_steps) == float(0): raise ValueError("plot start point and end point must be different") options = {} if nargs == 1: options['expect_one_var'] = True if is_Vector(funcs): funcs = list(funcs) #TODO: raise an error if there is a function/method in funcs that takes more values than we have ranges if return_vars: return fast_float(funcs, *vars, **options), [ tuple(range + [range_step]) for range, range_step in zip(ranges, range_steps) ], vars else: return fast_float(funcs, *vars, **options), [ tuple(range + [range_step]) for range, range_step in zip(ranges, range_steps) ]
def setup_for_eval_on_grid(funcs, ranges, plot_points=None, return_vars=False): """ Calculate the necessary parameters to construct a list of points, and make the functions fast_callable. INPUT: - ``funcs`` - a function, or a list, tuple, or vector of functions - ``ranges`` - a list of ranges. A range can be a 2-tuple of numbers specifying the minimum and maximum, or a 3-tuple giving the variable explicitly. - ``plot_points`` - a tuple of integers specifying the number of plot points for each range. If a single number is specified, it will be the value for all ranges. This defaults to 2. - ``return_vars`` - (default False) If True, return the variables, in order. OUTPUT: - ``fast_funcs`` - if only one function passed, then a fast callable function. If funcs is a list or tuple, then a tuple of fast callable functions is returned. - ``range_specs`` - a list of range_specs: for each range, a tuple is returned of the form (range_min, range_max, range_step) such that ``srange(range_min, range_max, range_step, include_endpoint=True)`` gives the correct points for evaluation. EXAMPLES:: sage: x,y,z=var('x,y,z') sage: f(x,y)=x+y-z sage: g(x,y)=x+y sage: h(y)=-y sage: sage.plot.misc.setup_for_eval_on_grid(f, [(0, 2),(1,3),(-4,1)], plot_points=5) (<sage.ext...>, [(0.0, 2.0, 0.5), (1.0, 3.0, 0.5), (-4.0, 1.0, 1.25)]) sage: sage.plot.misc.setup_for_eval_on_grid([g,h], [(0, 2),(-1,1)], plot_points=5) ((<sage.ext...>, <sage.ext...>), [(0.0, 2.0, 0.5), (-1.0, 1.0, 0.5)]) sage: sage.plot.misc.setup_for_eval_on_grid([sin,cos], [(-1,1)], plot_points=9) ((<sage.ext...>, <sage.ext...>), [(-1.0, 1.0, 0.25)]) sage: sage.plot.misc.setup_for_eval_on_grid([lambda x: x^2,cos], [(-1,1)], plot_points=9) ((<function <lambda> ...>, <sage.ext...>), [(-1.0, 1.0, 0.25)]) sage: sage.plot.misc.setup_for_eval_on_grid([x+y], [(x,-1,1),(y,-2,2)]) ((<sage.ext...>,), [(-1.0, 1.0, 2.0), (-2.0, 2.0, 4.0)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,-1,1),(y,-1,1)], plot_points=[4,9]) (<sage.ext...>, [(-1.0, 1.0, 0.6666666666666666), (-1.0, 1.0, 0.25)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,-1,1),(y,-1,1)], plot_points=[4,9,10]) Traceback (most recent call last): ... ValueError: plot_points must be either an integer or a list of integers, one for each range sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(1,-1),(y,-1,1)], plot_points=[4,9,10]) Traceback (most recent call last): ... ValueError: Some variable ranges specify variables while others do not sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(1,-1),(-1,1)], plot_points=5) doctest:...: DeprecationWarning: Unnamed ranges for more than one variable is deprecated and will be removed from a future release of Sage; you can used named ranges instead, like (x,0,2) See http://trac.sagemath.org/7008 for details. (<sage.ext...>, [(1.0, -1.0, 0.5), (-1.0, 1.0, 0.5)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], plot_points=5) (<sage.ext...>, [(1.0, -1.0, 0.5), (-1.0, 1.0, 0.5)]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(x,-1,1)], plot_points=5) Traceback (most recent call last): ... ValueError: range variables should be distinct, but there are duplicates sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,1),(y,-1,1)]) Traceback (most recent call last): ... ValueError: plot start point and end point must be different sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,1,-1),(y,-1,1)], return_vars=True) (<sage.ext...>, [(1.0, -1.0, 2.0), (-1.0, 1.0, 2.0)], [x, y]) sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(y,1,-1),(x,-1,1)], return_vars=True) (<sage.ext...>, [(1.0, -1.0, 2.0), (-1.0, 1.0, 2.0)], [y, x]) """ if max(map(len, ranges)) != min(map(len, ranges)): raise ValueError("Some variable ranges specify variables while others do not") if len(ranges[0])==3: vars = [r[0] for r in ranges] ranges = [r[1:] for r in ranges] if len(set(vars))<len(vars): raise ValueError("range variables should be distinct, but there are duplicates") else: vars, free_vars = unify_arguments(funcs) if len(free_vars)>1: from sage.misc.superseded import deprecation deprecation(7008, "Unnamed ranges for more than one variable is deprecated and will be removed from a future release of Sage; you can used named ranges instead, like (x,0,2)") # pad the variables if we don't have enough nargs = len(ranges) if len(vars)<nargs: vars += ('_',)*(nargs-len(vars)) ranges = [[float(z) for z in r] for r in ranges] if plot_points is None: plot_points=2 if not isinstance(plot_points, (list, tuple)): plot_points = [plot_points]*len(ranges) elif len(plot_points)!=nargs: raise ValueError("plot_points must be either an integer or a list of integers, one for each range") plot_points = [int(p) if p>=2 else 2 for p in plot_points] range_steps = [abs(range[1] - range[0])/(p-1) for range, p in zip(ranges, plot_points)] if min(range_steps) == float(0): raise ValueError("plot start point and end point must be different") options={} if nargs==1: options['expect_one_var']=True if is_Vector(funcs): funcs = list(funcs) #TODO: raise an error if there is a function/method in funcs that takes more values than we have ranges if return_vars: return fast_float(funcs, *vars,**options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)], vars else: return fast_float(funcs, *vars,**options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)]