maxima.interact() doesn't really interacts. Is this normal ?

70 views
Skip to first unread message

Emmanuel Charpentier

unread,
Aug 2, 2013, 8:54:05 AM8/2/13
to sage-s...@googlegroups.com
Maxima.console allows for direct communication between user and maxima, whereas maxima.interact still filters input and output. Compare :

sage: maxima.console()
;;; Loading #P"/home/charpent/sage-5.10/local/lib/ecl/sb-bsd-sockets.fas"
;;; Loading #P"/home/charpent/sage-5.10/local/lib/ecl/sockets.fas"
;;; Loading #P"/home/charpent/sage-5.10/local/lib/ecl/defsystem.fas"
;;; Loading #P"/home/charpent/sage-5.10/local/lib/ecl/cmp.fas"
using Lisp ECL 12.12.1
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
The function bug_report() provides bug reporting information.
(%i1) display2d:false;

(%o1) false
(%i2) declare(x,real,t,real,m,real,s,real) $ assume(s>0) $

(%i4) define(foo(x,m,s),subst((x-m)/s,x,diff(1/(1+%e^-x),x)));

(%o4) foo(x,m,s):=%e^-((x-m)/s)/(%e^-((x-m)/s)+1)^2
(%i5) integrate(foo(x,m,s),x,minf,inf);

(%o5) s
(%i6) integrate(foo(x,m,s)/s,x,minf,inf);

(%o6) 1
(%i7) integrate(x*foo(x,m,s)/s,x,minf,inf);

Is 1/s an integer?

n;    ;;; This is an answer  typed in the terminal
Is 2*m/s an integer?

n; ;;; Ditto
Is m/s an integer?

n; ;;; Ditto
(%o7) m
(%i8) quit();

with :

sage: maxima.interact() 

  --> Switching to Maxima <--

maxima: declare(x,real,t,real,m,real,s,real);
done
maxima: assume(s>0);
[s>0]
maxima: define(foo(x,m,s),subst((x-m)/s,x,diff(1/(1+%e^-x),x)));
foo(x,m,s):=%e^-((x-m)/s)/(%e^-((x-m)/s)+1)^2
maxima: integrate(foo(x,m,s),x,minf,inf);
s
maxima: integrate(foo(x,m,s)/s,x,minf,inf);
1
maxima: integrate(x*foo(x,m,s)/s,x,minf,inf);
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/home/charpent/sage-5.10/local/lib/python2.7/site-packages/IPython/core/prefilter.pyc in prefilter_lines(self, lines, continue_prompt)
    358                              for lnum, line in enumerate(llines) ])
    359         else:
--> 360             out = self.prefilter_line(llines[0], continue_prompt)
    361 
    362         return out

/home/charpent/sage-5.10/local/lib/python2.7/site-packages/IPython/core/prefilter.pyc in prefilter_line(self, line, continue_prompt)
    314         # At this point, we invoke our transformers.
    315         if not continue_prompt or (continue_prompt and self.multi_line_specials):
--> 316             line = self.transform_line(line, continue_prompt)
    317 
    318         # Now we compute line_info for the checkers and handlers

/home/charpent/sage-5.10/local/lib/python2.7/site-packages/IPython/core/prefilter.pyc in transform_line(self, line, continue_prompt)
    288         for transformer in self.transformers:
    289             if transformer.enabled:
--> 290                 line = transformer.transform(line, continue_prompt)
    291         return line
    292 

/home/charpent/sage-5.10/local/lib/python2.7/site-packages/sage/misc/interpreter.pyc in transform(self, line, continue_prompt)
    544                 line = 'InputForm[%s]'%line
    545 
--> 546             t = self.shell.interface.eval(line)
    547 
    548             #Once we've evaluated the lines, we can clear the queue

/home/charpent/sage-5.10/local/lib/python2.7/site-packages/sage/interfaces/expect.pyc in eval(self, code, strip, synchronize, locals, allow_use_file, split_lines, **kwds)
   1206                 elif split_lines:
   1207                     return '\n'.join([self._eval_line(L, allow_use_file=allow_use_file, **kwds)
-> 1208                                         for L in code.split('\n') if L != ''])
   1209                 else:
   1210                     return self._eval_line(code, allow_use_file=allow_use_file, **kwds)

/home/charpent/sage-5.10/local/lib/python2.7/site-packages/sage/interfaces/maxima.pyc in _eval_line(self, line, allow_use_file, wait_for_prompt, reformat, error_check, restart_if_needed)
    791             return out
    792 
--> 793         self._expect_expr()
    794         assert len(self._before())==0, 'Maxima expect interface is confused!'
    795 

/home/charpent/sage-5.10/local/lib/python2.7/site-packages/sage/interfaces/maxima.pyc in _expect_expr(self, expr, timeout)
    695                 self._sendline(";")
    696                 self._expect_expr()
--> 697                 raise ValueError, msg
    698         except KeyboardInterrupt, msg:
    699             #print self._expect.before

ValueError: Computation failed since Maxima requested additional constraints (try the command "maxima.assume('/s>0')" before integral or limit evaluation, for example):
Is 1/s an integer?
maxima: ;;; Here, I type Ctrl-D

  --> Exiting back to Sage <--

In the maxima.interact() call, sage "sees" the question from maxima, and acts accordingly (here, suggests an assumption that cannot be made...).

Is that the intended effect of maxima.interact ?

William Stein

unread,
Aug 2, 2013, 9:16:49 AM8/2/13
to sage-s...@googlegroups.com
Yes. maxima.console() fires up an entirely new maxima console (a
whole new session) and directly dumps the user into it.
maxima.interact() simply takes the existing maxima session -- the (or
a) one that Sage controls -- and lets the user directly type commands
to it and have results displayed back; all the interaction goes
through exactly the same mechanism (mainly pexpect) that Sage uses for
commands like maxima.eval. There are a dozen other interfaces that
have a .interact() method that works like this.

Implementing something like you want might be a good idea or
interesting though.

-- William



>
> --
> You received this message because you are subscribed to the Google Groups
> "sage-support" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sage-support...@googlegroups.com.
> To post to this group, send email to sage-s...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sage-support.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
William Stein
Professor of Mathematics
University of Washington
http://wstein.org

Emmanuel Charpentier

unread,
Aug 3, 2013, 6:34:44 AM8/3/13
to sage-s...@googlegroups.com
On 02/08/2013 15:16, William Stein wrote:
On Fri, Aug 2, 2013 at 5:54 AM, Emmanuel Charpentier
<emanuel.c...@gmail.com> wrote:
[ Snip... ]


      
In the maxima.interact() call, sage "sees" the question from maxima, and
acts accordingly (here, suggests an assumption that cannot be made...).

Is that the intended effect of maxima.interact ?
Yes.    maxima.console() fires up an entirely new maxima console (a
whole new session) and directly dumps the user into it.
maxima.interact() simply takes the existing maxima session -- the (or
a) one that Sage controls -- and lets the user directly type commands
to it and have results displayed back; all the interaction goes
through exactly the same mechanism (mainly pexpect) that Sage uses for
commands like maxima.eval.  There are a dozen other interfaces that
have a .interact() method that works like this.

Implementing something like you want might be a good idea or
interesting though.
Below, I try to clarify what I wanted to do :

Maxima is still Sage's main tool for symbolic analysis. However, it sometiomes needs information that the current pexpect() doesn't know how to process. Furtehrmore, it sometimes needs information that *cannot* be given in advance with Maxima's language. What I wanted was a way to interact *directly* with the *current* Maxima session through a "dumb" pipe, without pexpect() pre- and post-processing.

How I see things currently :

Default Maxima use :

User <--> Sage user interface <--> Sage processing <--> pexpect <--> Sage's maxima

maxima.console()

User <--> Sage user interface <--> dumb pipe <--> New maxima

maxima.interact()

User <--> Sage user interface <--> pexpect <--> Sage's maxima

What I (think I) want :

User <--> Sage user interface <--> dumb pipe <--> Sage's Maxima

What I think what I want entails :

User <--> Sage user interface <-+-> dumb pipe <--------------------+-> Sage's Maxima
                                |                                  |
                                +-> Sage processing <--> pexpect <-+

The points marked by "+" on  the top line are switches controlled by Sage (with states : "normal use" or "my interact") controlling :
  • On Maxima's  end :
    • where maxima input stream should come from
    • where maxima's output qnd error streams should go to
  • On Sage's end :
    • where Sage user interface output should go to
    • where Sage user interface input should come from.
The trick is, of course, to maintain them synchronous.

This can be done, I think, by implementing just a bidirectional (tridirectional ?) dumb pipe from Sage's maxima to Sage and implementing the switching in Sage.

I think that in various unices, this is easily done. Not quite so sure abour Windows (even with Cygwin), since windows has no real fork().

What do you think ?

                    Emmanuel Charpentier

Nils Bruin

unread,
Aug 10, 2013, 10:40:22 PM8/10/13
to sage-s...@googlegroups.com


On Saturday, August 3, 2013 3:34:44 AM UTC-7, Emmanuel Charpentier wrote:
Maxima is still Sage's main tool for symbolic analysis.
That's not entirely true. There are quite a few basic manipulations that get handled by pynac directly. There are essential features that only maxima provides, though, so your point still stands.
 
However, it sometiomes needs information that the current pexpect() doesn't know how to process.

Note that the maxima that gets used for symbolic work is *NOT* driven via a pexpect interface. ECL (lisp) is running as a library, with maxima loaded.  Communication via strings is not the only way to pass information back and forth: lisp and python data structures are close enough that in many cases a more direct (and faster!) translation can be used. For instance, integration and limit evaluation are currently NOT driven by passing strings back and forth. It would be straightforward, but quite a bit of work, to banish essentially all string-passing. Nobody has deemed it worth going through all code and doing so, however.
 
When strings do get passed back and forth, it is not done via pexpect, but by calling maxima's "parse this string and evaluate it" on a string that's sitting in memory.

Furthermore, it sometimes needs information that *cannot* be given in advance with Maxima's language. What I wanted was a way to interact *directly* with the *current* Maxima session through a "dumb" pipe, without pexpect() pre- and post-processing.

You can, but you'd have to build your own pipe, a la:

sage: while true:
....:     print "maxima input:",
....:     sys.stdout.flush()
....:     R=sys.stdin.readline()
....:     print maxima_calculus.eval(R)
maxima input:1+2
 3
maxima input:4+5
 9
maxima input:integrate(x^3+x/cos(x),x)
 2*'integrate((x*sin(x)*sin(2*x)+x*cos(x)*cos(2*x)+x*cos(x))/(sin(2*x)^2+cos(2*x)^2+2*cos(2*x)+1),x)+x^4/4
maxima input:^C
KeyboardInterrupt

It's important to realize that what you see printed here is NOT printed by maxima. These are string representations of the values returned by the maxima expression evaluations. I think we're redirecting ECL's idea of stdout to /dev/null, because some of maxima's verbosity is painful. You can change that back if you think that's necessary, but you'll have to look up in maxima_lib 's initialization what the incantation for that is.

In principle, it would be possible to allow ECL to read and write to the standard in/out and run maxima's proper REPL, but getting control back might be tricky. It should also be not necessary: You can send any maxima instruction straight to the process to be evaluated.
 
Default Maxima use :

User <--> Sage user interface <--> Sage processing <--> pexpect <--> Sage's maxima

So we don't do that! we do

... Sage processing --> construct a lisp S-EXPR in the ECL library --> call ECL library to evaluate the S-EXPR --> process the result of the evaluation

In both the "construct" and "process" phase, we may evaluate other ECL code to do string processing
 
maxima.console()

User <--> Sage user interface <--> dumb pipe <--> New maxima

maxima.interact()

User <--> Sage user interface <--> pexpect <--> Sage's maxima

Both work, but you're not talking to the maxima that gets used for standard symbolic work.
 
What I (think I) want :

User <--> Sage user interface <--> dumb pipe <--> Sage's Maxima

You're not getting a "dumb pipe", but you can pass strings directly to maxima_calculus for evaluation and get the result back (as a string). Side effects should influence further command evaluations and further sage symbolic work, as they would in a normal maxima session.
    • where maxima input stream should come from
    • where maxima's output qnd error streams should go to
  • On Sage's end :
    • where Sage user interface output should go to
    • where Sage user interface input should come from.
On Maxima's  end : The trick is, of course, to maintain them synchronous.

The good news is: there's no synchronization, because the interface is just via library calls, not via streams.
The (slightly) bad news is: you're not really communicating with a Maxima session through the normal stdin/stdout channels,  so if you want to do things that are really dependent on that, you may have to adapt a little. However, it sounds like you want to just nudge maxima a little. That should be straightforward.

I think that in various unices, this is easily done. Not quite so sure abour Windows (even with Cygwin), since windows has no real fork().

There should be no issue under cygwin, other than getting the code to compile and run properly. No special facilities are needed.
 
Reply all
Reply to author
Forward
0 new messages