# HP Forums

Full Version: HP Prime CAS programming
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
There are several methods to make use of CAS commands in a program on the HP Prime.

1. CAS("command(arg1,arg2,...,argn)")
2. CAS.command("arg1","arg2",...,"argn") or CAS.command("arg1,arg2,...,argn")
3. Create an actual CAS function via #cas and #end

Recall that an HP Prime Programming Language (HPPPL) program is essentially a collection of commands that are executed in the Home view. And in the Home view, most CAS commands must be treated with care. Techniques 1 and 2 behave mostly the same, and are generally used within HPPPL programs to gain access to CAS commands. Technique 3 is equivalent to creating a function in the CAS view, but the function remains resident in storage even after the use of the 'restart' command. This needs further clarification: the program's source remains in storage, however the command must be "re-compiled" in order to reuse it. Thus, technique 3 is more akin to creating a macro file that needs to be run (i.e. "compiled") after each instance of the 'restart' command. This is the advantage of creating an HPPPL program that uses techniques 1 and 2 since HPPPL programs are always resident in memory after compilation (there is no 'restart' equivalent for Home view).

Example of Technique 1

Suppose we wish to create a program that takes a formula for the function \( f(x) \) and determine the values of \( x \) such that \( f'(x) = 0 \). For our example, let \( f(x) = x^3-3x \). If we do this by hand in the CAS view, we would likely type in:

Code:
```f:=x^3-3*x; derf:=diff(f,x); solve(derf,x);```

and obtain the list: { -1, 1 }. We could simplify these steps into:

solve(diff(f,x),x);

This simplification allows us to create the following program:

Code:
```EXPORT CASCMD1(f) BEGIN   local cmd:="solve(diff(" + f + ",x),x)";   CAS(cmd); END;```

To actually use the program, we must type: CASCMD1("x^3-3*x"). Notice that the argument f is actually a string representing the expression \( x^3-3x \). Some important points:
• We CANNOT use CAS("solve(diff" + f + ",x),x)") in place of CAS(cmd). That is, the argument of CAS() must either be a string or a variable whose content is a string, and the string must be a valid CAS input. The argument of the CAS() command must not be an expression, since the CAS() command will then simply evaluate the expression in the CAS view -- i.e. it will simply add the three strings using the CAS view rules.
• It is possible to save the results using, say, L1:=CAS(cmd); to save the results into the built-in list L1. More generally, one may store the result into any variable whether local or global or built-in.
• Sometimes the "type" of the result may be altered due to differences in how the CAS and Home views represent that type. For example, one may create a symbolic matrix for the input variable f (in the form of a string) and the result is converted into a list of lists. Accessing the entries is still the same, but any type checks will require extra care.
• If we have result:=CAS(cmd); then we can (generally) use 'result' without having to convert it into a string.
• We can create a CAS variable via: CAS("casvar:=0"); -- of course, change 'casvar' accordingly.

Example of Technique 2

Again, under the same premise as in the previous example, we can create the following code:

Code:
```EXPORT CASCMD2(f)   local result:=CAS.diff(f,"x");   result:=CAS.solve(result,"x"); END;```

We can use 'result' directly with the solve() command. If, however, we had wanted to solve the equation \( f'(x) = -3 \), or equivalently \( f'(x) + 3 = 0 \) then it is NOT simply a matter of changing the last line of code to: result:=CAS.solve(result+3,"x"); because the expression result+3 is computed as if we were in the Home view. And in the Home view, the content of 'result' -- which is the expression '3*x^2-3' -- must be resolvable. If the variable 'x' does not exist, then an error occurs. So the following modification is required:

Code:
```// modification so that we solve f'(x)=-3 EXPORT CASCMD2(f)   local result:=CAS.diff(f,"x");   result:=STRING(result) + "+3"; // or simply result:=STRING(result) + 3; since HPPPL can auto-convert where there is no ambiguity   result:=CAS.solve(result,"x"); END;```

Example of Technique 3

The simplest (in terms of coding and legibility of code) is by creating a CAS function. The easiest way to create a CAS program is to simply "solve" our problem in the CAS view. Then, open the program editor and create a new CAS program. Finally, simply copy and paste (from the CAS view) the relevant commands used in the previous session.

Code:
```#cas CASCMD3(f):= BEGIN   derf:=diff(f,x);   solve(derf,x); END; #end```

Some important notes:
• This program will create a CAS variable named derf. If we want derf to be only temporary, then we can create a local variable named derf.
• Local variables must necessarily be declared first (it seems). Otherwise a syntax error occurs. Moreover, we cannot combine a declaration with an assignment as in non-CAS programs. So local derf:=<blah> would not be allowed. Below is an example of the use of a local CAS variable.
Code:
```#cas CASCMD3(f):= BEGIN   local derf;   derf:=diff(f,x);   solve(derf,x); END; #end```
• In the CAS view, the input to our program can be typed without the " symbol. In the Home view, our program (being a CAS command) requires that the input be quoted with the " symbol.

The Hybrid Approach

It is also possible to create a hybrid project. That is, a single source file could potentially have both non-CAS programs _and_ CAS programs. For example:

Code:
```EXPORT NONCAS(f) BEGIN   CAS.diff(f,"x"); END; #cas CASPROG(f):= BEGIN   local result;   result:=NONCAS(f);   solve(result,x); END; #end```

CASPROG("x^3-3*x") from the Home view will return { -1, 1 }.

Pros and Cons

There are benefits as well as drawbacks to using each technique. As of firmware 6975:
• Local variables in CAS programs MUST be declared at the beginning of each procedure. Moreover, the declarations must be separate from initialization. So whereas local foo:=bar; is completely fine for non-CAS programs, this single line must be split into local foo; foo:=bar; for CAS programs.
• CAS programs may be programmed to have dynamic input. For example,
Code:
```#cas myprog(args):= BEGIN   local s:=SIZE(args);   CASE     IF s==0 THEN       // code for when no arguments supplied     END;     IF s==1 THEN       // code for when a single argument is supplied     END;   END; END; #end```
may be called with myprog(), myprog(arg1), myprog(arg1,arg2), ... etc. Note that a more complete check would also include the TYPE() of the variable s (since using SIZE() on matrices will return the result: [ row column ]). The program must, of course, properly handle the various combinations of inputs. In order to achieve an equivalent program in HPPPL, we could implement something like:
Code:
```EXPORT myprogram(arg) BEGIN   local s:=SIZE(arg);   CASE     IF s==1 THEN       // we have a non-list argument; perhaps dispatch based on type of argument     END;     IF s>1 THEN       // we have a list; dispatch based on size of list       CASE         IF s==2 THEN           // blah         END;         IF s==3 THEN           // blah         END;       END; // inner case    END; // if s>1   END; // outer case      END;```
This program would be called with myprog(arg1) OR myprog({arg1}), myprog({arg1,arg2}), myprog({arg1,arg2,arg3}), etc. Unfortunately there does not seem to be a way to accept the hybrid case: both no argument or variable number of arguments.
• Non-CAS programs currently have a more usable (though still broken) debugger.
• Non-CAS programs do not have to be "recompiled"; CAS programs must be "recompiled" should one use the restart command in CAS view.
• Pure CAS programs do not have to deal with type conversion between CAS and non-CAS programs.
• Non-CAS programs that use CAS commands will generally have to involve string manipulation.
• Non-CAS programs can make use of "interface" commands such as CHOOSE() and INPUT() whereas CAS programs are generally not interactive. A workaround is to use the EXPR() command to call these commands indirectly. EXPR() works like CAS() in that both take input strings.
• Both non-CAS and CAS programs must carefully account for the fact that some commands are case sensitive. Generally speaking, upper-case commands are Home-view commands whereas lower-case commands are CAS-view commands. In HPPPL, most of the time, there is no distinction between cases. That is, the command TYPE() and type() are no different. However, CAS-only commands must be typed in lower-case (e.g. mat2list() is a CAS command that works in Home view, but only if typed as mat2list() and not MAT2LIST() -- the latter does not exist). CAS programs, however, DO distinguish between TYPE() and type().
• All variables not declared as local are considered global CAS variables and persist even after the program finishes. Thus, programmers may possibly have to use purge() to clean up any mess their programs leave.
• The equality == behaves differently in CAS vs non-CAS. For example: in the CAS view, testing equality between a list and a real value returns a 0 (due to type checking, perhaps?) whereas in the Home view testing equality between a list and a real value applies the test to the entire list, resulting in a list of 0's and 1's.
• I'm sure there are more....
Thank you, Han,
I'm bookmarking this guide, very interesting for me.

Please, explain also something about how pass arguments, i.e how pass an optional argument...

Have a nice day!

***
EDIT:
please, Han, advise, if possible, how to make a Help for a customized program.
I would like to help about the list of parameters when the program start (or pressing Help key, but I don't know if it's possible)...
Thank you very much Han, for theses explanations. I am very interested in this Chapter. I will follow assiduously this post.

In my mind local variables were prohibited in the CAS side... And for me instructions inside #CAS #end (in a non cas program) were carried out only once during compilation (a kind of script)... Can we place several blocks #cas #end in a source file ?
(02-19-2015 08:21 PM)Han Wrote: [ -> ]There are several methods to make use of CAS commands in a program on the HP Prime...

...When I have time, I'll add more to this. There is still a lot more to discuss (e.g. the scope of CAS variables inside a HPPPL program and vice versa), but this should allow many folks to get started with CAS programming.

This is excellent Han, even after all this time, your article has cleared up many details and annoyances with CAS, at least for me. Thanks very much!

Suggestion: Move this post to the "Articles" Forum, intended for reference works like this.

Moderator suggestion: Possible addition of a new "Prime Articles" forum. The Prime is so vast and new, and complex to learn, that a dedicated place for articles such as this would be tremendously helpful to folks new to the Prime and/or the forum, where they can pick from a small, focused set of instructional articles. While there is a wealth of info stuffed into the current Prime forum now, a reader must wade through hundreds of threads with thousands of messages to find the dozen or so seminal articles that explain and illustrate with examples many of the most confusing and/or complex issues learning Prime.
(02-20-2015 01:22 PM)rprosperi Wrote: [ -> ]Suggestion: Move this post to the "Articles" Forum, intended for reference works like this.

Eventually, it will be moved. I find it more helpful to write about topics that are more important to users and prefer to this forum for the simple fact that it allows replies and keeps the discussion to a single thread. So for now (since it's nowhere finished), I thought I'd post here so that people can post replies/suggestions/criticisms/etc since that sort of discussion is not allowed in the articles forum.
(02-21-2015 03:21 AM)Han Wrote: [ -> ]So for now (since it's nowhere finished), I thought I'd post here so that people can post replies/suggestions/criticisms/etc since that sort of discussion is not allowed in the articles forum.

I agree!
TU
(02-21-2015 03:21 AM)Han Wrote: [ -> ]
(02-20-2015 01:22 PM)rprosperi Wrote: [ -> ]Suggestion: Move this post to the "Articles" Forum, intended for reference works like this.

Eventually, it will be moved. I find it more helpful to write about topics that are more important to users and prefer to this forum for the simple fact that it allows replies and keeps the discussion to a single thread. So for now (since it's nowhere finished), I thought I'd post here so that people can post replies/suggestions/criticisms/etc since that sort of discussion is not allowed in the articles forum.

I agree completely, sorry if not clear; it's much more useful for future readers once the "discussion" has been captured here. My suggesition is just that; compose and discuss here, intereacting with folks to capture the most common questions and answers on this topic, and once "complete", move it to a (general or Prime-dedicated) Articles forum so new users seeking instruction can find it easily.

And thanks for conducting class here, it's very helpful.
(02-19-2015 08:41 PM)salvomic Wrote: [ -> ]Thank you, Han,
I'm bookmarking this guide, very interesting for me.

Please, explain also something about how pass arguments, i.e how pass an optional argument...

Have a nice day!

***
EDIT:
please, Han, advise, if possible, how to make a Help for a customized program.
I would like to help about the list of parameters when the program start (or pressing Help key, but I don't know if it's possible)...

One way is to mimic commands from *nix environments. Create a CAS program that acts as a wrapper for the program. The CAS program should handle dynamic input so that if no input is given, it spits out the help. Otherwise, the wrapper sends it to the actual program.

Code:
``` #cas wrapper(arg):= BEGIN   local s;   s:=SIZE(arg);   IF s==0 THEN RETURN("Usage: command(matrix, real, list)"); END;   IF s==3 THEN DOMYPROG(arg(1),arg(2),arg(3)); END;   // etc. END; #end```
Thanks Han!

This is one of the reasons the Prime is unusable as a reliable and time saving tool, extremely inconsistent and unintuitive handling and results.

Have been trying to make something work that I have spent hours trying to solve before.. Would you please show me how to use "quorem" using arguments in a nonCAS program? Would be REALLY helpful!

Like (this obviously don't work..):

EXPORT TEST(x,y)
BEGIN
CAS.quorem(x,y);
END;
(03-30-2015 04:29 PM)pr0 Wrote: [ -> ]Thanks Han!

This is one of the reasons the Prime is unusable as a reliable and time saving tool, extremely inconsistent and unintuitive handling and results.

Have been trying to make something work that I have spent hours trying to solve before.. Would you please show me how to use "quorem" using arguments in a nonCAS program? Would be REALLY helpful!

Like (this obviously don't work..):

EXPORT TEST(x,y)
BEGIN
CAS.quorem(x,y);
END;

This works fine when I try TEST([1,2,3,4],[-1,2]). However, it seems that quorem() is broken when using double-quoted arguments such as:

quorem("x^3+2*x^2+3*x+4","-x+2")

My suspicion is that both vectors and strings are pointer-based, and the parser is probably mis-interpreting the string as a vector (I get [undef] as the result). I think you may have found a bug either in the CAS parser or the quorem command itself.
Una publicación en Español fuera del foro: Programación CAS
I am not sure if this is an obvious or rediculous question:

a CAS function is listed under "Mem"->"CAS Vars". The system seems to be aware of the CAS function being a (Function).
Is it possible to have these 'Cas Vars' listed like in the Toolbox? Is that even a problem for others?

I feel like I forget what functions i have implemented AND it would be way faster to call a function by choosing it under 'Toolbox'/'CAS functions'/name than being forced to remember and type its name.
(01-22-2020 12:21 PM)leprechaun Wrote: [ -> ]I am not sure if this is an obvious or rediculous question:

a CAS function is listed under "Mem"->"CAS Vars". The system seems to be aware of the CAS function being a (Function).
Is it possible to have these 'Cas Vars' listed like in the Toolbox? Is that even a problem for others?

I feel like I forget what functions i have implemented AND it would be way faster to call a function by choosing it under 'Toolbox'/'CAS functions'/name than being forced to remember and type its name.

You don't need to type their names. They are available in the [Vars] (CAS) menus.
The problem is we cannot tell if it is variable or a function as the CAS doesn't really make that distinction in a way we have access to.
Thank you! That is what I was asking for. I did a good amount of trying out menus and keys and I could could swear there was nothing shown, but obviously it is there. No idea why I have not found it prior to posting....

thanks again
An alternative way to define functions is to use the following template

PHP Code:
`#casfunction name(args)   ...   return ...end;#end `

and you can even delete the directive. #end

PHP Code:
`#casfunction name(args)   ...   return ...end; `

Example with the new template
PHP Code:
`#casfunction fract2(X_,Y_,Nmax)  local x,y,z,c,j,w,h,res1,res2;  freeze;  w:=2.7/X_;  h:=-1.87/Y_;  res1:=[];   Y_:=Y_-1;  for y from 0 to Y_ do    c:=-2.1+i*(h*y+0.935);    for x from 0 to X_-1 do      z:=0;      for j from 0 to Nmax-1 do        if abs(z:=z^2+c)>2 then break; end;      end;      res1.append(pixon_p(x,y,126*j+2079));      c:=c+w;    end;   end;   return "Done"end;#end `
fract2(320,240,10)

standard notation for CAS programs

PHP Code:
`#casname(args):=begin   ...   return ...end;#end `

PHP Code:
`#casname(args):=begin   ...   return ...end; `

PHP Code:
`#casfract1(X_,Y_,Nmax):=BEGIN  local x,y,z,c,j,w,h,res1,res2;  freeze;  w:=2.7/X_;  h:=-1.87/Y_;  res1:=[];   Y_:=Y_-1;  for y from 0 to Y_ do    c:=-2.1+i*(h*y+0.935);    for x from 0 to X_-1 do      z:=0;      for j from 0 to Nmax-1 do        if abs(z:=z^2+c)>2 then break; end;      end;      res1.append(pixon_p(x,y,126*j+2079));      c:=c+w;    end;   end;   return "Done"END;#end `
(01-22-2020 01:15 PM)Tim Wessman Wrote: [ -> ]The problem is we cannot tell if it is variable or a function as the CAS doesn't really make that distinction in a way we have access to.

Maybe it should provide a bit as a flag for that?
VPN
(01-22-2020 01:15 PM)Tim Wessman Wrote: [ -> ]The problem is we cannot tell if it is variable or a function as the CAS doesn't really make that distinction in a way we have access to.

a function in CAS, internally contains the -> symbol or the block -> BEGIN END

which will identify the type of data function of a symbolic variable

1:
PHP Code:
`#cas function casprg() return ABS(x+y*i); end; `

is recoded as

PHP Code:
`casprg := ( seq[ ] ) -> RETURN( ABS( x + y*i ) ) `

while a variable does not contain the -> symbol

casvar1 := x+y*i

2:
PHP Code:
`#cas function casprg1() local r;  r:= ABS(x+y*i); return r; end; `

is recoded as
PHP Code:
`casprg1 := ( seq[ ] )->BEGIN   LOCAL r;   r:=ABS(x+y*i);    RETURN(r);  END; `
CAS programs are expressions of root node 'program' (with a child of type DOM_LIST, a list of 3 arguments). If f is a variable containing a program (for example defined like this f(x):=sin(x)), type(f) will return DOM_FUNC and f[1] or f[0] (depends whether Python compatibility is enabled) is 'program'.
In contrast, if g:=sin(x), g is an expression of rootnode 'sin' (with x as child) and g[1] or g[0] is 'sin'.
I have been very interested in understanding how to call CAS functions from HOME (thinking about including these calls in a HOME program or a custom app). So I found this post extremely interesting, although the original hints have some years. Thus, I have done some tests with firmware version 2.1.14433 (2020 01 21), using variables of string type and in the end the options that work for me are summarised in this small program:
Code:
```EXPORT TEST() BEGIN LOCAL RES1, RES2, CMD1:="diff(3*x^2+5*x)"; RES1:=CAS.diff("3*x^2+5*x"); RES2:=CAS(EVAL(CMD1)); RETURN RES2; END;```
This program calls the diff() CAS command to differenciate an expression. It works both in CAS as in HOME screens. The result in HOME screen is '3*2*x+5'; in CAS screen, the output is '6*x+5' (it is simplified). It is possible to edit the RETURN line to RETURN RES1, obtaining the same outcome. Notice the application of the EVAL command.
Pages: 1 2
Reference URL's
• HP Forums: https://www.hpmuseum.org/forum/index.php
• :