source: sage/interfaces/magma.py @ 3:6ee487e4d475

Revision 3:6ee487e4d475, 7.4 KB checked in by tornaria@…, 7 years ago (diff)

[project @ patch to sage-1.0.0.1]

Line 
1r"""
2Interface to Magma
3
4\note{You must have \code{magma} installed on your computer
5for this interface to work.   Magma is not free, so it is
6not included with \sage, but you can obtain it from
7\url{http://magma.maths.usyd.edu.au/}.}   You do not
8have to install any optional \sage packages.
9
10
11SAGE provides an interface to the Magma computational algebra
12system.  This system provides extensive functionality for
13number theory, group theory, combinatorics and algebra.
14
15The Magma interface offers three pieces of functionality:
16\begin{enumerate}
17
18\item \code{magma_console()} -- A function that dumps you
19into an interactive command-line Magma session. 
20
21\item \code{magma(expr)} -- Evaluation of arbitrary Magma
22expressions, with the result returned as a string.
23
24\item \code{magma.new(expr)} -- Creation of a SAGE object that wraps a
25Magma object.  This provides a Pythonic interface to Magma.  For example,
26if \code{f=magma.new(10)}, then \code{f.Factors()} returns the prime
27factorization of $10$ computed using Magma.
28
29\end{enumerate}
30
31
32
33\subsection{Parameters}
34Some Magma functions have optional ``parameters'', which
35are arguments that in Magma go after a colon.  In SAGE,
36you pass these using named function arguments.  For example,
37
38    sage: E = magma.new('EllipticCurve([0,1,1,-1,0])')
39    sage: E.Rank(Bound = 5)
40    0
41
42\subsection{Multiple Return Values}
43
44Some Magma functions return more than one value.
45You can control how many you get using the \code{nvals}
46named parameter to a function call:
47
48    sage: n = magma.new(100)
49    sage: n.IsSquare(nvals = 1)
50    true
51    sage: n.IsSquare(nvals = 2)
52    (true, 10)
53
54\subsection{Long Input}
55The Magma interface reads in even very long input (using files) in a
56robust manner.
57
58    sage: t = '"%s"'%10^10000   # ten thousand character string.
59    sage: a = magma.eval(t)           
60    sage: a = magma(t)
61"""
62
63#*****************************************************************************
64#       Copyright (C) 2005 William Stein <wstein@ucsd.edu>
65#
66#  Distributed under the terms of the GNU General Public License (GPL)
67#
68#    This code is distributed in the hope that it will be useful,
69#    but WITHOUT ANY WARRANTY; without even the implied warranty of
70#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
71#    General Public License for more details.
72#
73#  The full text of the GPL is available at:
74#
75#                  http://www.gnu.org/licenses/
76#*****************************************************************************
77
78from sage.structure.element import RingElement
79from expect import console, Expect, ExpectElement, FunctionElement
80PROMPT = ">>>"
81
82class Magma(Expect):
83    """
84    Interface to the Magma interpreter.
85    """
86    def __init__(self, maxread=10000, script_subdirectory="user", logfile=None, server=None):
87        Expect.__init__(self,
88                        name = "magma",
89                        prompt = ">",
90                        command = "magma -b -n", 
91                        maxread = maxread,
92                        server = server, 
93                        script_subdirectory = script_subdirectory,
94                        restart_on_ctrlc = True,
95                        logfile = logfile,
96                        eval_using_file_cutoff=100)
97        # We use "-n" above in the Magma startup command so
98        # local user startup changes are not read.
99
100        self.__seq = 0
101
102    def __reduce__(self):
103        return reduce_load_Magma, tuple([])
104
105    def _read_in_file_command(self, filename):
106        return 'load "%s";'%filename
107
108    def eval(self, x):
109        x = str(x).rstrip()
110        if len(x) == 0 or x[len(x) - 1] != ';':
111            x += ';'
112        ans = Expect.eval(self, x).replace('\\\n','')
113        if ans.find("Runtime error") != -1:
114            raise RuntimeError, "Error evaluation Magma code.\nIN:%s\nOUT:%s"%(x, ans)
115        return ans
116
117    def _start(self):
118        self._change_prompt('>')
119        Expect._start(self)
120        self.eval('SetPrompt("%s"); SetLineEditor(false); SetColumns(0);'%PROMPT)
121        self._change_prompt(PROMPT)
122        self.expect().expect(PROMPT)
123        self.expect().expect(PROMPT)
124
125    def set(self, var, value):
126        """
127        Set the variable var to the given value.
128        """
129        out = self.eval("%s := %s"%(var, value))
130        if out.lower().find("error") != -1:
131            raise TypeError, "Error executing Magma code:\n%s"%out
132
133    def get(self, var):
134        """
135        Get the value of the variable var.
136        """
137        return self.eval("%s"%var)
138
139    #def clear(self, var):
140    #    """
141    #    Clear the variable named var.
142    #    """
143        #self.eval("delete %s"%var)
144    #    self.eval("%s:=0"%var)
145       
146    def attach(self, filename):
147        self.eval('Attach("%s")'%filename)
148
149    def _next_var_name(self):
150        if self.__seq == 0:
151            self.eval('sage := [* *];')
152        else:
153            self.eval('Append(~sage, 0);')
154        self.__seq += 1
155        return 'sage[%s]'%self.__seq
156
157    def function_call(self, function, args=[], params={}, nvals=1):
158        if not isinstance(args, list):
159            args = [args]
160        for i in range(len(args)):
161            if not isinstance(args[i], ExpectElement):
162                args[i] = self(args[i])
163        nvals = int(nvals)
164        if len(params) == 0:
165            par = ''
166        else:
167            par = ' : ' + ','.join(['%s:=%s'%(a,b) for a,b in params.items()])
168           
169        fun = "%s(%s%s)"%(function, ",".join([s.name() for s in args]), par)
170        if nvals <= 0:
171            out = self.eval(fun)
172            ans = None
173        elif nvals == 1:
174            return self(fun)
175        else:
176            v = [self._next_var_name() for _ in range(nvals)]
177            vars = ", ".join(v)
178            cmd = "%s := %s;"%(vars, fun)
179            out = self.eval(cmd)
180            ans = tuple([MagmaElement(self, x, is_name = True) for x in v])
181       
182        if out.lower().find("error") != -1:
183            raise TypeError, "Error executing Magma code:\n%s"%out
184        return ans
185           
186    #def new(self, x):
187    #    if isinstance(x, MagmaElement) and x.parent() == self:
188    #        return x
189    #    return MagmaElement(self, x)
190
191    def _object_class(self):
192        return MagmaElement
193       
194    def _left_list_delim(self):
195        return "[*"
196
197    def _right_list_delim(self):
198        return "*]"
199   
200    def console(self):
201        magma_console()
202
203    def version(self):
204        return magma_version()
205
206class MagmaFunctionElement(FunctionElement):
207    def __call__(self, *args, **kwds):
208        nvals = 1
209        if len(kwds) > 0:
210            if kwds.has_key('nvals'):
211                nvals = kwds['nvals']
212                del kwds['nvals']
213        M = self._obj.parent()
214        return M.function_call(self._name,
215                               [self._obj.name()] + list(args),
216                               params = kwds,
217                               nvals = nvals)
218
219    def help(self):
220        M = self._obj.parent()
221        t = str(self.Type())
222        return M(self._name)
223   
224
225class MagmaElement(ExpectElement):
226    def __getattr__(self, attrname):
227        return MagmaFunctionElement(self, attrname)
228
229    def methods(self):
230        return self.parent()('ListSignatures(%s)'%self.Type())
231   
232       
233
234
235magma = Magma()
236
237def reduce_load_Magma():
238    return magma
239
240def magma_console():
241    console('magma')
242
243def magma_version():
244    t = tuple([int(n) for n in magma.eval('GetVersion()').split()])
245    return t, 'V%s.%s-%s'%t
Note: See TracBrowser for help on using the repository browser.