r""" Interface to REDUCE REDUCE \url{http://www.reduce-algebra.com/} is a free interactive system for general algebraic computations of interest to mathematicians, scientists and engineers. [[Replace this by something relevant to your system.]] Type \code{gp.[tab]} for a list of all the functions available from your Gp install. Type \code{gp.[tab]?} for Gp's help about a given function. Type \code{gp(...)} to create a new Gp object, and \code{gp.eval(...)} to run a string using Gp (and get the result back as a string). EXAMPLES: To start Reduce under sage: sage: import sage.interfaces.reduce as r Reduce examples from $reduce/doc/misc/intro.tex: Polynomials, rational functions: sage: r.reduce('coeff(x**3 + 3*x**2*y + 3*x*y**2 + y**3,x)') {y**3,3*y**2,3*y,1} sage: r.reduce('gcd(x**2 + 4*x + 3,x**2 - 2*x - 3)') x + 1 sage: r.reduce('resultant(x**2 + 4*x + 3,x**2 - 2*x - 3,x)') 0 sage: r.reduce('decompose(x**6+6x**4+x**3+9x**2+3x-5)') {u**2 + u - 5,u=x**3 + 3*x} sage: r.reduce('factorize(x**6+6x**4+x**3+9x**2+3x)') {{x**3 + 3*x + 1,1},{x**2 + 3,1},{x,1}} sage: r.reduce('roots(x**6+6x**4+x**3+9x**2+3x-5)') {x= - 0.775167, x= - 0.271781 + 1.79488*i, x= - 0.271781 - 1.79488*i, x=0.387584 + 1.8576*i, x=0.387584 - 1.8576*i, x=0.543562} sage: r.reduce('interpol({0,7,26,63},z,{1,2,3,4})') z**3 - 1 Partial fraction decomposition: sage: r.reduce('pf(2/((x+1)^2*(x+2)),x)') {2/(x + 2),( - 2)/(x + 1),2/(x**2 + 2*x + 1)} Matrices: sage: r.reduce('m:=mat((1,x),(2,y))') mat((1,x),(2,y)) sage: r.reduce('1/m') mat((( - y)/(2*x - y),x/(2*x - y)),(2/(2*x - y),( - 1)/(2*x - y))) sage: r.reduce('det m') - 2*x + y Ordinary differential equations: sage: r.reduce('odesolve(df(y,x)=y+x**2+2,y,x)') {y=e**x*arbconst(1) - x**2 - 2*x - 4} Linear system (hidden): sage: r.reduce('solve({(a*x+y)/(z-1)-3,y+b+z,x-y}, \ ....: {x,y,z})') {{x=( - 3*b - 3)/(a + 4), y=( - 3*b - 3)/(a + 4), z=( - a*b - b + 3)/(a + 4)}} Transcendental equations: sage: r.reduce('solve(a**(2*x)-3*a**x+2,x)') {x=(2*arbint(2)*i*pi + log(2))/log(a),x=(2*arbint(1)*i*pi)/log(a)} Polynomial systems: sage: r.reduce('solve( \ ....: { a*c1 - b*c1**2 - g*c1*c2 + e*c3, \ ....: -g*c1*c2 + (e+t)*c3 -k*c2, \ ....: g*c1*c2 + k*c2 - (e+t) * c3}, \ ....: {c3,c2,c1})') {{c3=( - c1**3*b*g + c1**2*a*g - c1**2*b*k + c1*a*k)/(c1*g*t - e*k), c2=( - c1**2*b*e - c1**2*b*t + c1*a*e + c1*a*t)/(c1*g*t - e*k), c1=arbcomplex(3)}} Structural analysis: sage: r.reduce('load compact') sage: r.reduce('compact(s*(1-(sin x**2)) \ ....: +c*(1-(cos x)**2) \ ....: +(sin x)**2+(cos x)**2, \ ....: {cos x^2+sin x^2=1})') cos(x)**2*s + sin(x)**2*c + 1 Calculus: sage: r.reduce('df(exp(x**2)/x,x,2)') (2*e**(x**2)*(2*x**4 - x**2 + 1))/x**3 sage: r.reduce('int(x^3*exp(2x),x)') (e**(2*x)*(4*x**3 - 6*x**2 + 6*x - 3))/8 sage: r.reduce('limit(x*sin(1/x),x,infinity)') 1 Series: sage: r.reduce('on rounded; load taylor') sage: r.reduce('taylor(sin(x+1),x,0,4)') taylor(0.841470984808 + 0.540302305868*x - 0.420735492404*x**2 - 0.0900503843114 *x**3 + 0.0350612910337*x**4,x,0,4) sage: r.reduce('off rounded') sage: r.reduce('sum(n,n)') (n*(n + 1))/2 sage: r.reduce('prod(n/(n+2),n)') 2/(n**2 + 3*n + 2) Complex numbers: sage: r.reduce('w:=(x+3*i)**2') 6*i*x + x**2 - 9 Rounded numbers: sage: r.reduce('on rounded; precision 25') sage: r.reduce('pi**2') 9.869604401089358618834491 sage: r.reduce('off rounded') Modular numbers: sage: r.reduce('on modular; setmod 17') sage: r.reduce('(x-1)**2') x**2 + 15*x + 1 sage: r.reduce('factorize ws') {{x + 16,2}} sage: r.reduce('off modular') To get 2d ASCII art for formulas use: sage: f = r.reduce('1/(x-1)^3'); f 1/(x**3 - 3*x**2 + 3*x - 1) sage: f.display2d() 1 --------------------- 3 2 x - 3*x + 3*x - 1 sage: print f 1 --------------------- 3 2 x - 3*x + 3*x - 1 To try to transform to native Sage object use: sage: sf = f._sage_() sage: sf 1/(x^3 - 3*x^2 + 3*x - 1) sage: type(sf) AUTHORS: -- William Stein (template) & Richard Liska """ ########################################################################## # # Copyright (C) 2006 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ # ########################################################################## from expect import Expect, ExpectElement, ExpectFunction, FunctionElement from sage.misc.misc import verbose class Reduce(Expect): """ [[Some basic help about your system. This is what will be displayed when somebody write reduce?.]] """ def __init__(self, stacksize=10000000, # 10MB maxread=100000, script_subdirectory=None, logfile='/tmp/sage-reduce.log', server=None, init_list_length=1024): Expect.__init__(self, # The capitalized versionof this is used for printing. name = 'reduce', # This is regexp of the input prompt. If you can change # it to be very obfuscated that would be better. Even # better is to use sequence numbers. prompt = '[1-9]: ', # This is the command that starts up your program # command = "reduce_tty", command = "reduce_algebra", maxread = maxread, server=server, script_subdirectory = script_subdirectory, # If this is true, then whenever the user presses Control-C to # interrupt a calculation, the whole interface is restarted. restart_on_ctrlc = False, # If true, print out a message when starting # up the command when you first send a command # to this interface. verbose_start = False, init_code=['off int$ off nat$'], logfile=logfile, # If an input is longer than this number of characters, then # try to switch to outputing to a file. eval_using_file_cutoff=1024) self.__seq = 0 self.__var_store_len = 0 self.__init_list_length = init_list_length def eval(self, code, strip=True): code += ';\n' s = Expect.eval(self, code, strip)[1:] s = s.replace('$','') # print " in eval: \n",s return s def _install_hints(self): """ Hints for installing Reduce interface on your computer. AUTHORS: - William Stein and Richard Liska (2010-01-08) """ return """ In order to use the Reduce interface you need to have Reduce installed and have a script in your PATH called "reduce_algebra" that runs the command-line version of Reduce. You might get free Reduce computer algebra system at http://www.reduce-algebra.com. """ def _repr_(self): return 'Reduce Interpreter' def __reduce__(self): """ EXAMPLES:: sage: maxima.__reduce__() (, ()) """ return reduce_load_Reduce, tuple([]) # def __getattr__(self, attrname): # if attrname[:1] == "_": # raise AttributeError # return ReduceFunction(self, attrname) def _quit_string(self): """ EXAMPLES:: sage: r.reduce._quit_string() 'quit' :: sage: r.reduce('2+2') sage: r.reduce.is_running() True sage: r.reduce.quit() sage: r.reduce.is_running() False To reload Reduce interface: sage: r.reduce.quit() sage: reload(sage.interfaces.reduce) """ return 'quit' def _read_in_file_command(self, filename): r""" Returns the string used to read filename into Maple. EXAMPLES:: sage: maple._read_in_file_command('test') 'in "test"' :: sage: filename = tmp_filename() sage: f = open(filename, 'w') sage: f.write('xx := 22;\n') sage: f.close() sage: r.reduce.read(filename) sage: r.reduce('xx') '22' """ return 'in "%s"'%filename def trait_names(self): ## [[implement giving a list of all functions and identifiers in the system]] pass # def read(self, filename): # # [[implement loading of the contents of filename into the system]] # pass def kill(self, var): # [[send code that kills the variable with given name in the system.]] pass def console(self): """ Spawn a new Maple command-line session. EXAMPLES:: sage: r.reduce.console() REDUCE 3.8, 15-Apr-2004, patched to 30-May-2005 ... 1: """ reduce_console() def version(self): # run the version command (defined below) # reduce_version(self) return Expect.eval(self, 'lisp(version!*);', True)[1:] def _object_class(self): return ReduceElement def _true_symbol(self): # return the string rep of truth, i.e., what the system outputs # when you type 1==1. return 't' def _assign_symbol(self): return ':=' def _false_symbol(self): # return the string rep of truth, i.e., what the system outputs # when you type 1==2. return '0' def _equality_symbol(self): # return the symbol for checking equality, e.g., == or eq. return '=' def help(self, command): # return help on a given command. pass import re class ReduceElement(ExpectElement): """ Describe elements of your system here. """ def trait_names(self): # This is if your system doesn't really have types. If you have types # this function should only return the relevant methods that thake self # as their firce argument. return self.parent().trait_names() #reduce_tick = re.compile("[a-z|0-9|_]*") def _sage_(self): """ Attempt to make a native Sage object out of this maxima object. This is useful for automatic coercions in addition to other things. EXAMPLES:: sage: a3 = r.reduce('(x+y)**2'); a3 x**2 + 2*x*y + y**2 sage: b3 = a3._sage_() sage: type(b3) sage: ai = r.reduce('(i+1)^3');ai 2*(i - 1) sage: bi = ai._sage_() sage: type(bi) sage: bi 2*I - 2 sage: aso = r.reduce('solve({(a*x+y)/(z-1)-3,y+b+z,x-y},{x,y,z})');aso {{x=( - 3*b - 3)/(a + 4), y=( - 3*b - 3)/(a + 4), z=( - a*b - b + 3)/(a + 4)}} sage: baso = aso._sage_();baso [[x == -3*(b + 1)/(a + 4), y == -3*(b + 1)/(a + 4), z == -(a*b + b - 3)/(a + 4)]] sage: type(baso) """ from sage.calculus.calculus import symbolic_expression_from_string from sage.misc.multireplace import multiple_replace from sage.rings.infinity import infinity, Infinity reduce_symtable = {'pi':'pi', 'e': 'e', 'i':'I', '{':'[', '}':']'} #, 'infinity':'oo'} # print " here " s = repr(self) # print s # print reduce_symtable s = multiple_replace(reduce_symtable, s) # print s # warning: Reduce does not do arithmetic with infinity!! # syms = {'infinity': Infinity} # does not work - gives InfInIty syms = {} # formal_functions = reduce_tick.findall(s) # print formal_functions # if len(formal_functions) > 0: # for X in formal_functions: # syms[X[1:]] = function(X[1:]) # print syms return symbolic_expression_from_string(s,syms,accept_sequence=True) def __str__(self): """ Printing an object explicitly gives ASCII art: EXAMPLES:: sage: f = r.reduce('1/(x-1)^3'); f 1/(x-1)^3 sage: print f 1 --------------------- 3 2 x - 3*x + 3*x - 1 """ return self.display2d(onscreen=False) def display2d(self, onscreen=True): """ EXAMPLES:: sage: F = r.reduce('(x+1)**5') sage: F.display2d () 5 4 3 2 x + 5*x + 10*x + 10*x + 5*x + 1 """ self._check_valid() s = repr(self) P = self.parent() P.eval('on nat') s = P.eval(s) P.eval('off nat') if onscreen: print s else: return s def is_ReduceElement(x): return isinstance(x, ReduceElement) # An instance reduce = Reduce() def reduce_load_Reduce(): """ EXAMPLES:: sage: from sage.interfaces.reduce import reduce_load_Reduce sage: reduce_load_Reduce() Reduce Interpreter """ return reduce import os def reduce_console(): os.system('reduce_algebra') def reduce_version(self): """ EXAMPLES: sage: reduce.version() ??? """