Installing racket-cas

I finally got round to trying @soegaard 's racket-cas and on the whole it seems OK but I'm not sure I've installed it correctly, there are some minor issues and the docs seem unclear.

I downloaded the zip from github and ran drracket from its directory.
Is it supposed to be installed as a package under raco? I didn't do that, maybe I was supposed to.

To get it to run I then had to modify main.rkt a bit, and then loaded that up into my DrRacket IDE. Here's the file:

#lang racket
(require "racket-cas.rkt")
(require "repl.rkt")

(provide (all-from-out "racket-cas.rkt"))

When I run this, the greeting appears OK, and the basic commands see to work fine, eg

> (tex (expand '(expt (+ a b) 2)))
"$a^{2}+b^{2}+2\\cdot {a\\cdot b}$"

Typing plain x y or z also correctly reads them as 'x 'y or 'z

What does not happen is automatic simplification, which the docs say should happen. However if I explicitly request simplification, it seems OK.

> `(+ 3 a 2 x (* 4 x))
'(+ 3 a 2 x (* 4 x))
> (simplify `(+ 3 a 2 x (* 4 x)))
'(+ 5 a (* 5 x))

Any suggestions?
(Especially if this should be installed as a package? The suggestion to use the form
(require racket-cas/repl)
instead of how I did it makes me think so.)

Thanks!

Thanks for taking the time to test racket-cas.

You are right there is an issue with the quasiquote when required.
It's a scope issue (I believe) - maybe someone can spot the problem [see later].

However, you can open the file repl.rkt directly and run it.
Then quasiquote, `, will work in the repl:

Note however, that automatic simplification and simplify is two different things. The automatic simplifier only does "small stuff" (adds numbers, collect equal terms, sort the terms etc.).

The functions in racket-cas usually expect their inputs to be normalized.
If the inputs are normalized, the outputs are also normalized.
Therefore the automatic simplifier (aka normalize) must be used on inputs
before calling many of the functions.

In the repl it is more convenient to use quasiquote than it is to writenormalize` all the time.

But, back to the macro problem. The "make quasiquote do automatic simplification" macro is defined in [1].

The question is why it works when used in "repl.rkt" but not when required from the repl?

(module+ start
  (provide quote quasiquote)
  (require (submod ".."))
  (require (prefix-in old: (only-in racket/base quote quasiquote)))
  ; In the REPL it can be convenient to change the meaning of ' 
  ; to automatic normalization:
  (define-syntax (quote stx) 
    (syntax-case stx () [(_ . datum) #'(normalize (old:quote . datum))]))
  (define-syntax (quasiquote stx) 
    (syntax-case stx () [(_ . datum) #'(normalize (old:quasiquote . datum))])))

; (let () (define f '(* x x)) `(* x ,f))  

; This macro doesn't work as expected ... why?
(define-syntax (repl stx) 
  (syntax-case stx () 
    [_ (with-syntax ([req (datum->syntax stx 'require)])
         (syntax/loc stx (req (submod "." start))))]))

[1] racket-cas/racket-cas/racket-cas.rkt at master · soegaard/racket-cas · GitHub

Where you're doing (provide (all-from-out "racket-cas.rkt")), does it help to also provide all-from-out "repl.rkt"?

Thanks for all that, Axel!
Yes, indeed, opening repl.rkt instead of main.rkt fixes the normalization/auto-simplification issue
(@AlexKnauth , no, just adding all-from-out does not fix it, but it doesn't matter, since you can just launch off the repl.rkt file)

Looking forward to testing it and seeing how it's been implemented!

There is one more little thing I found, I think it may be due to an update in Racket since it was written, I'm guessing it was a keyword parameter change

> (render (expand '(expt (+ a b) 2)))
. . racket-cas.rkt:2065:23: application: required keyword argument not supplied
  procedure: latex->pict
  required keyword: #:preamble
  arguments...:

Any ideas? - it would be nice to have a renderer that can be shown off...

Where are you trying to use the repl macro? It seems like the "." in the submod would only work if it's already in the same module anyway.

I think, the problem that render used to be defined in racket-cas but was removed.
Now it calls a render from latex-pict, which is broken.
[I'll fix that.]

In the mean time, you can paste this definition into the repl to get a render.

    (begin (require latex-pict pict)
                 (define (render u)
                   (define (strip$ x) (substring x 1 (- (string-length x) 1)))
                   (pict->bitmap (scale (tex-math (strip$ (tex u))) 2))))

Erm, almost but not quite

> (begin (require latex-pict pict)
                 (define (render u)
                   (define (strip$ x) (substring x 1 (- (string-length x) 1)))
                   (pict->bitmap (scale (tex-math (strip$ (tex u))) 2))))
> (render (normalize '(+ x 2 a 3 (* 4 x))))
exec failed (No such file or directory; errno=2)
. . ../../usr/share/racket/collects/racket/private/kw.rkt:1386:57: open-input-file: cannot open input file
  path: /var/tmp/latex2pdf-6d322b6d01941cdd976b954807b0591c.log
  system error: No such file or directory; errno=2

You can see it flash momentarily as it tries to open a rendering window, but then it reports the above error about not being able to find some log file, no idea what that is, I'm afraid. Permissions?

Anyway it really is not a high priority for me, I'm more than happy to wait till it's fixed, but it certainly would be nice to have, once everything's going. Just thought I'd let you know.

The package latex-pict uses pdflatex and a couple of latex libraries.
Maybe something is configured differently on your computer?
If you are using a complete, newish TeXLive, I'd expect everything to work.
Marc had to install some extra packages to get everything to work though.

See

I expect pdflatex is in the path?

pdflatex was not on the path.

It is now, it's still failing, but with less error output :grin:

(render (normalize '(+ x 2 a 3 (* 4 x))))
. . ../../usr/share/racket/collects/racket/private/kw.rkt:1386:57: latex failed

I'll look into it later, I'm more involved with the math now.

====
PS. The offending line was:

                                ;; caller didn't lift expressions out
                                (let ([ids (generate-temporaries args)])
>1386....................>>>      #`(let #,(map list ids
                                          (map hide-binding-name args))
                                              #,(k ids)))

if that helps at all

Which editor are you using in your screenshot? Mine doesn't really look like that in DrRacket or Emacs, and I'm wondering if there's another editor you're using that I haven't tried.

@cadence

It's just Emacs.
I have over time stolen bits and pieces from Eli, Greg and Bogdan
and added keybindings that work more-or-less like DrRacket.

See:

2 Likes

@soegaard Hey Jens,
I just wanted to say that the racket-cas library is really nice, works well and has saved me a ton of work for now!

I mean, I know everybody wants to write their own, and so do I :crazy_face: but until then, this is really super.

Many, many thanks!

1 Like

That's great to hear!

Yeah, especially the subst functionality, which allows me to combine it with normal Racket functional code is a boon.
I'm sure I'll be plaguing you with some questions in the future, and once I've got my head around it a bit, I'll be happy to look through the source, see if there's anywhere I can help!
Have a great Festive Season...

(define (unapply expr var) (λ(x) (subst expr var x)))
((unapply '(+ x (* 2 y)) 'x) 3)
==> '(+ 3 (* 2 y))
((unapply '(+ x (* 2 y)) 'y) 3)
==> '(+ 6 x)
1 Like

As I said, I've been getting along with racket-cas faster than I thought I would.
The idea is to make a generalised math package, gjs-stylee, perhaps ultimately a bit like scmutils. For this, I need to be able to move transparently between numeric and symbolic code. Also I need functions to evaluate "normally" when dealing with inexact values, but symbolically when dealing with exact or symbolic ones. Like my 80s TI-Voyage on its puny m68k, is that too much to ask? :smile:
Anyway, the racket-cas library seems really easy to interact with , I've managed to encapsulate it acceptably so far. See, the racket-cas notation is "hidden", expressions are generated by regular functions.

; sorry, not done expt yet  
(define (power expr i)    (expand ((repeat-apply (curry * expr) i) 1)))
> (power (+ 'x 1) 6)
(+ 1 (* 6 x) (* 15 (expt x 2)) (* 20 (expt x 3)) (* 15 (expt x 4)) (* 6 (expt x 5)) (expt x 6))

@soegaard Really nice to have those expand and distribute functionalities so easily available but (if I may ask) did you deliberately not incorporate them into simplification routines? Just out of curiosity.

Also how can I get the docs into html or pdf or whatever? I tried running

scribble --html racket-cas.scrbl

but to no avail. I also tried to pass it that info file, but I must be doing something basically wrong.

Really nice to have those expand and distribute functionalities so easily available but (if I may ask) did you deliberately not incorporate them into simplification routines? Just out of curiosity.

Yes. Consider (x+y)^100000. This is a small expression whose expansion is large. This choice matches Mathematica, NSpire and other.

I'll need to check that's the issue with the docs.

Btw - since you mention that you also need numerical calculations.
The compile function exported by racket-cas can be used to convert S-expressions into normal, callable functions.

Example from the README.

We can use standard plot library to draw a few graphs of the Taylor polynomials.
The plot library expects standard Racket functions from number to number.
The function  compile  will turn a symbolic expression into a normal Racket function.
    > (require plot)
    > (plot (list (function (compile (taylor '(sin x) x 0 5)) #:color "green")
                  (function sin #:color "red" -3.14 3.14)))
    <nice graphs appear in DrRacket>

I tried scribble --html racket-cas.scrbl and scribble --pdf racket-cas.scrbl and they worked for me (at least after running raco setup).

Hmm. I can't attach pdfs?

I'll send a mail instead.

1 Like

Ah, great, thanks, I was about to look into that (compile). Looks useful, especially if the results are faster than whatever clunky solutions.

BTW, teeny typo in readme

(compile (taylor '(sin 'x) 'x 0 5))

Erm, I never ran raco setup first, should I have? What does it set up that isn't already set up?

Apropos typo: Sorry, I took the example out of context.
Earlier in the readme, I have:

> (require racket-cas/auto-quote)
> x
'x

The auto-quote feature turns unbound references into symbols.
A feature meant to be used in the repl only.

I don't think it is needed to run raco setup first - but I had a new installation and had to before it scribble ran as expected.