Next: Formatting Lisp Functions, Previous: Vector Lisp Functions, Up: Internals

The functions described here operate on symbolic formulas in the Calculator.

— Function: **calc-prepare-selection**` num`

Prepare a stack entry for selection operations. If

numis omitted, the stack entry containing the cursor is used; otherwise, it is the number of the stack entry to use. This function stores useful information about the current stack entry into a set of variables.`calc-selection-cache-num`

contains the number of the stack entry involved (equal tonumif you specified it);`calc-selection-cache-entry`

contains the stack entry as a list (such as`calc-top-list`

would return with`entry`

as the selection mode); and`calc-selection-cache-comp`

contains a special “tagged” composition (see Formatting Lisp Functions) which allows Calc to relate cursor positions in the buffer with their corresponding sub-formulas.A slight complication arises in the selection mechanism because formulas may contain small integers. For example, in the vector ‘

[1, 2, 1]’ the first and last elements are`eq`

to each other; selections are recorded as the actual Lisp object that appears somewhere in the tree of the whole formula, but storing`1`

would falsely select both`1`

's in the vector. So`calc-prepare-selection`

also checks the stack entry and replaces any plain integers with “complex number” lists of the form ‘(cplx’. This list will be displayed the same as a plainn0)nand the change will be completely invisible to the user, but it will guarantee that no two sub-formulas of the stack entry will be`eq`

to each other. Next time the stack entry is involved in a computation,`calc-normalize`

will replace these lists with plain numbers again, again invisibly to the user.

— Function: **calc-encase-atoms**` x`

This modifies the formula

xto ensure that each part of the formula is a unique atom, using the ‘(cplx’ trick described above. This function may usen0)`setcar`

to modify the formula in-place.

— Function: **calc-find-selected-part**

Find the smallest sub-formula of the current formula that contains the cursor. This assumes

`calc-prepare-selection`

has been called already. If the cursor is not actually on any part of the formula, this returns`nil`

.

— Function: **calc-change-current-selection**` selection`

Change the currently prepared stack element's selection to

selection, which should be`eq`

to some sub-formula of the stack element, or`nil`

to unselect the formula. The stack element's appearance in the Calc buffer is adjusted to reflect the new selection.

— Function: **calc-find-nth-part**` expr n`

Return the

nth sub-formula ofexpr. This function is used by the selection commands, and (unlessj bhas been used) treats sums and products as flat many-element formulas. Thus ifexpris ‘((a + b) - c) + d’, calling`calc-find-nth-part`

withnequal to four will return ‘d’.

— Function: **calc-find-parent-formula**` expr part`

Return the sub-formula of

exprwhich immediately containspart. Ifexpris ‘a*b + (c+1)*d’ andpartis`eq`

to the ‘c+1’ term ofexpr, then this function will return ‘(c+1)*d’. Ifpartturns out not to be a sub-formula ofexpr, the function returns`nil`

. Ifpartis`eq`

toexpr, the function returns`t`

. This function does not take associativity into account.

— Function: **calc-find-assoc-parent-formula**` expr part`

This is the same as

`calc-find-parent-formula`

, except that (unlessj bhas been used) it continues widening the selection to contain a complete level of the formula. Given ‘a’ from ‘((a + b) - c) + d’,`calc-find-parent-formula`

will return ‘a + b’ but`calc-find-assoc-parent-formula`

will return the whole expression.

— Function: **calc-grow-assoc-formula**` expr part`

This expands sub-formula

partofexprto encompass a complete level of the formula. Ifpartand its immediate parent are not compatible associative operators, or ifj bhas been used, this simply returnspart.

— Function: **calc-find-sub-formula**` expr part`

This finds the immediate sub-formula of

exprwhich containspart. It returns an indexnsuch that ‘(calc-find-nth-part’ would returnexprn)part. Ifpartis not a sub-formula ofexpr, it returns`nil`

. Ifpartis`eq`

toexpr, it returns`t`

. This function does not take associativity into account.

— Function: **calc-replace-sub-formula**` expr old new`

This function returns a copy of formula

expr, with the sub-formula that is`eq`

tooldreplaced bynew.

— Function: **simplify**` expr`

Simplify the expression

exprby applying Calc's algebraic simplifications. This always returns a copy of the expression; the structureexprpoints to remains unchanged in memory.More precisely, here is what

`simplify`

does: The expression is first normalized and evaluated by calling`normalize`

. If any`AlgSimpRules`

have been defined, they are then applied. Then the expression is traversed in a depth-first, bottom-up fashion; at each level, any simplifications that can be made are made until no further changes are possible. Once the entire formula has been traversed in this way, it is compared with the original formula (from before the call to`normalize`

) and, if it has changed, the entire procedure is repeated (starting with`normalize`

) until no further changes occur. Usually only two iterations are needed: one to simplify the formula, and another to verify that no further simplifications were possible.

— Function: **simplify-extended**` expr`

Simplify the expression

expr, with additional rules enabled that help do a more thorough job, while not being entirely “safe” in all circumstances. (For example, this mode will simplify ‘sqrt(x^2)’ to ‘x’, which is only valid whenxis positive.) This is implemented by temporarily binding the variable`math-living-dangerously`

to`t`

(using a`let`

form) and calling`simplify`

. Dangerous simplification rules are written to check this variable before taking any action.

— Function: **simplify-units**` expr`

Simplify the expression

expr, treating variable names as units whenever possible. This works by binding the variable`math-simplifying-units`

to`t`

while calling`simplify`

.

— Macro: **math-defsimplify**` funcs body`

Register a new simplification rule; this is normally called as a top-level form, like

`defun`

or`defmath`

. Iffuncsis a symbol (like`+`

or`calcFunc-sqrt`

), this simplification rule is applied to the formulas which are calls to the specified function. Or,funcscan be a list of such symbols; the rule applies to all functions on the list. Thebodyis written like the body of a function with a single argument called`expr`

. The body will be executed with`expr`

bound to a formula which is a call to one of the functionsfuncs. If the function body returns`nil`

, or if it returns a result`equal`

to the original`expr`

, it is ignored and Calc goes on to try the next simplification rule that applies. If the function body returns something different, that new formula is substituted forexprin the original formula.At each point in the formula, rules are tried in the order of the original calls to

`math-defsimplify`

; the search stops after the first rule that makes a change. Thus later rules for that same function will not have a chance to trigger until the next iteration of the main`simplify`

loop.Note that, since

`defmath`

is not being used here,bodymust be written in true Lisp code without the conveniences that`defmath`

provides. If you prefer, you can havebodysimply call another function (defined with`defmath`

) which does the real work.The arguments of a function call will already have been simplified before any rules for the call itself are invoked. Since a new argument list is consed up when this happens, this means that the rule's body is allowed to rearrange the function's arguments destructively if that is convenient. Here is a typical example of a simplification rule:

(math-defsimplify calcFunc-arcsinh (or (and (math-looks-negp (nth 1 expr)) (math-neg (list 'calcFunc-arcsinh (math-neg (nth 1 expr))))) (and (eq (car-safe (nth 1 expr)) 'calcFunc-sinh) (or math-living-dangerously (math-known-realp (nth 1 (nth 1 expr)))) (nth 1 (nth 1 expr)))))This is really a pair of rules written with one

`math-defsimplify`

for convenience; the first replaces ‘arcsinh(-x)’ with ‘-arcsinh(x)’, and the second, which is safe only for real ‘x’, replaces ‘arcsinh(sinh(x))’ with ‘x’.

— Function: **common-constant-factor**` expr`

Check

exprto see if it is a sum of terms all multiplied by the same rational value. If so, return this value. If not, return`nil`

. For example, if called on ‘6x + 9y + 12z’, it would return 3, since 3 is a common factor of all the terms.

— Function: **cancel-common-factor**` expr factor`

Assuming

expris a sum withfactoras a common factor, divide each term of the sum byfactor. This is done by destructively modifying parts ofexpr, on the assumption that it is being used by a simplification rule (where such things are allowed; see above). For example, consider this built-in rule for square roots:(math-defsimplify calcFunc-sqrt (let ((fac (math-common-constant-factor (nth 1 expr)))) (and fac (not (eq fac 1)) (math-mul (math-normalize (list 'calcFunc-sqrt fac)) (math-normalize (list 'calcFunc-sqrt (math-cancel-common-factor (nth 1 expr) fac)))))))

— Function: **frac-gcd**` a b`

Compute a “rational GCD” of

aandb, which must both be rational numbers. This is the fraction composed of the GCD of the numerators ofaandb, over the GCD of the denominators. It is used by`common-constant-factor`

. Note that the standard`gcd`

function uses the LCM to combine the denominators.

— Function: **map-tree**` func expr many`

Try applying Lisp function

functo various sub-expressions ofexpr. Initially, callfuncwithexpritself as an argument. If this returns an expression which is not`equal`

toexpr, applyfuncagain until eventually it does returnexprwith no changes. Then, ifexpris a function call, recursively applyfuncto each of the arguments. This keeps going until no changes occur anywhere in the expression; this final expression is returned by`map-tree`

. Note that, unlike simplification rules,funcfunctions maynotmake destructive changes toexpr. If a third argumentmanyis provided, it is an integer which says how many timesfuncmay be applied; the default, as described above, is infinitely many times.

— Function: **compile-rewrites**` rules`

Compile the rewrite rule set specified by

rules, which should be a formula that is either a vector or a variable name. If the latter, the compiled rules are saved so that later`compile-rules`

calls for that same variable can return immediately. If there are problems with the rules, this function calls`error`

with a suitable message.

— Function: **apply-rewrites**` expr crules heads`

Apply the compiled rewrite rule set

crulesto the expressionexpr. This will make only one rewrite and only checks at the top level of the expression. The result`nil`

if no rules matched, or if the only rules that matched did not actually change the expression. Theheadsargument is optional; if is given, it should be a list of all function names that (may) appear inexpr. The rewrite compiler tags each rule with the rarest-looking function name in the rule; if you specifyheads,`apply-rewrites`

can use this information to narrow its search down to just a few rules in the rule set.

— Function: **rewrite-heads**` expr`

Compute a

headslist forexprsuitable for use with`apply-rewrites`

, as discussed above.

— Function: **rewrite**` expr rules many`

This is an all-in-one rewrite function. It compiles the rule set specified by

rules, then uses`map-tree`

to apply the rules throughoutexprup tomany(default infinity) times.

— Function: **match-patterns**` pat vec not-flag`

Given a Calc vector

vecand an uncompiled pattern set or pattern set variablepat, this function returns a new vector of all elements ofvecwhich do (or don't, ifnot-flagis non-`nil`

) match any of the patterns inpat.

— Function: **deriv**` expr var value symb`

Compute the derivative of

exprwith respect to variablevar(which may actually be any sub-expression). Ifvalueis specified, the derivative is evaluated at the value ofvar; otherwise, the derivative is left in terms ofvar. If the expression contains functions for which no derivative formula is known, new derivative functions are invented by adding primes to the names; see Calculus. However, ifsymbis non-`nil`

, the presence of nondifferentiable functions inexprinstead cancels the whole differentiation, and`deriv`

returns`nil`

instead.Derivatives of an

n-argument function can be defined by adding a`math-derivative-`

nproperty to the property list of the symbol for the function's derivative, which will be the function name followed by an apostrophe. The value of the property should be a Lisp function; it is called with the same arguments as the original function call that is being differentiated. It should return a formula for the derivative. For example, the derivative of`ln`

is defined by(put 'calcFunc-ln\' 'math-derivative-1 (function (lambda (u) (math-div 1 u))))The two-argument

`log`

function has two derivatives,(put 'calcFunc-log\' 'math-derivative-2 ; d(log(x,b)) / dx (function (lambda (x b) ... ))) (put 'calcFunc-log\'2 'math-derivative-2 ; d(log(x,b)) / db (function (lambda (x b) ... )))

— Function: **tderiv**` expr var value symb`

Compute the total derivative of

expr. This is the same as`deriv`

, except that variables other thanvarare not assumed to be constant with respect tovar.

— Function: **integ**` expr var low high`

Compute the integral of

exprwith respect tovar. See Calculus, for further details.

— Macro: **math-defintegral**` funcs body`

Define a rule for integrating a function or functions of one argument; this macro is very similar in format to

`math-defsimplify`

. The main difference is that herebodyis the body of a function with a single argument`u`

which is bound to the argument to the function being integrated, not the function call itself. Also, the variable of integration is available as`math-integ-var`

. If evaluation of the integral requires doing further integrals, the body should call ‘(math-integral’ to find the integral ofx)xwith respect to`math-integ-var`

; this function returns`nil`

if the integral could not be done. Some examples:(math-defintegral calcFunc-conj (let ((int (math-integral u))) (and int (list 'calcFunc-conj int)))) (math-defintegral calcFunc-cos (and (equal u math-integ-var) (math-from-radians-2 (list 'calcFunc-sin u))))In the

`cos`

example, we define only the integral of ‘cos(x) dx’, relying on the general integration-by-substitution facility to handle cosines of more complicated arguments. An integration rule should return`nil`

if it can't do the integral; if several rules are defined for the same function, they are tried in order until one returns a non-`nil`

result.

— Macro: **math-defintegral-2**` funcs body`

Define a rule for integrating a function or functions of two arguments. This is exactly analogous to

`math-defintegral`

, except thatbodyis written as the body of a function with two arguments,uandv.

— Function: **solve-for**` lhs rhs var full`

Attempt to solve the equation ‘

’ by isolating the variablelhs=rhsvaron the lefthand side; return the resulting righthand side, or`nil`

if the equation cannot be solved. The variablevarmust appear at least once inlhsorrhs. Note that the return value is a formula which does not containvar; this is different from the user-level`solve`

and`finv`

functions, which return a rearranged equation or a functional inverse, respectively. Iffullis non-`nil`

, a full solution including dummy signs and dummy integers will be produced. User-defined inverses are provided as properties in a manner similar to derivatives:(put 'calcFunc-ln 'math-inverse (function (lambda (x) (list 'calcFunc-exp x))))This function can call ‘

(math-solve-get-sign’ to create a new arbitrary sign variable, returningx)xtimes that sign, and ‘(math-solve-get-int’ to create a new arbitrary integer variable multiplied byx)x. These functions simply returnxif the caller requested a non-“full” solution.

— Function: **solve-eqn**` expr var full`

This version of

`solve-for`

takes an expression which will typically be an equation or inequality. (If it is not, it will be interpreted as the equation ‘’.) It returns an equation or inequality, orexpr= 0`nil`

if no solution could be found.

— Function: **solve-system**` exprs vars full`

This function solves a system of equations. Generally,

exprsandvarswill be vectors of equal length. See Solving Systems of Equations, for other options.

— Function: **expr-contains**` expr var`

Returns a non-

`nil`

value ifvaroccurs as a subexpression ofexpr.This function might seem at first to be identical to

`calc-find-sub-formula`

. The key difference is that`expr-contains`

uses`equal`

to test for matches, whereas`calc-find-sub-formula`

uses`eq`

. In the formula ‘f(a, a)’, the two ‘a’s will be`equal`

but not`eq`

to each other.

— Function: **expr-contains-count**` expr var`

Returns the number of occurrences of

varas a subexpression ofexpr, or`nil`

if there are no occurrences.

— Function: **expr-depends**` expr var`

Returns true if

exprrefers to any variable the occurs invar. In other words, it checks ifexprandvarhave any variables in common.

— Function: **expr-contains-vars**` expr`

Return true if

exprcontains any variables, or`nil`

ifexprcontains only constants and functions with constant arguments.

— Function: **expr-subst**` expr old new`

Returns a copy of

expr, with all occurrences ofoldreplaced bynew. This treats`lambda`

forms specially with respect to the dummy argument variables, so that the effect is always to returnexprevaluated atold=new.

— Function: **multi-subst**` expr old new`

This is like

`expr-subst`

, except thatoldandneware lists of expressions to be substituted simultaneously. If one list is shorter than the other, trailing elements of the longer list are ignored.

— Function: **expr-weight**` expr`

Returns the “weight” of

expr, basically a count of the total number of objects and function calls that appear inexpr. For “primitive” objects, this will be one.

— Function: **expr-height**` expr`

Returns the “height” of

expr, which is the deepest level to which function calls are nested. (Note that ‘’ counts as a function call.) For primitive objects, this returns zero.a+b

— Function: **polynomial-p**` expr var`

Check if

expris a polynomial in variable (or sub-expression)var. If so, return the degree of the polynomial, that is, the highest power ofvarthat appears inexpr. For example, for ‘(x^2 + 3)^3 + 4’ this would return 6. This function returns`nil`

unlessexpr, when expanded out bya x(`calc-expand`

), would consist of a sum of terms in whichvarappears only raised to nonnegative integer powers. Note that ifvardoes not occur inexpr, thenexpris considered a polynomial of degree 0.

— Function: **is-polynomial**` expr var degree loose`

Check if

expris a polynomial in variable or sub-expressionvar, and, if so, return a list representation of the polynomial where the elements of the list are coefficients of successive powers ofvar: ‘’ would produce the list ‘a+bx +cx^3(’, and ‘ab0c)(x + 1)^2’ would produce the list ‘(1 2 1)’. The highest element of the list will be non-zero, with the special exception that ifexpris the constant zero, the returned value will be ‘(0)’. Return`nil`

ifexpris not a polynomial invar. Ifdegreeis specified, this will not consider polynomials of degree higher than that value. This is a good precaution because otherwise an input of ‘(x+1)^1000’ will cause a huge coefficient list to be built. Iflooseis non-`nil`

, then a looser definition of a polynomial is used in which coefficients are no longer required not to depend onvar, but are only required not to take the form of polynomials themselves. For example, ‘sin(x) x^2 + cos(x)’ is a loose polynomial with coefficients ‘((calcFunc-cos x) 0 (calcFunc-sin x))’. The result will never be`nil`

in loose mode, since any expression can be interpreted as a “constant” loose polynomial.

— Function: **polynomial-base**` expr pred`

Check if

expris a polynomial in any variable that occurs in it; if so, return that variable. (Ifexpris a multivariate polynomial, this chooses one variable arbitrarily.) Ifpredis specified, it should be a Lisp function which is called as ‘(’, and which should return true ifpredsubexpr)`mpb-top-expr`

(a global name for the originalexpr) is a suitable polynomial insubexpr. The default predicate uses ‘(polynomial-p mpb-top-expr’; you can usesubexpr)predto specify additional conditions. Or, you could havepredbuild up a list of every suitablesubexprthat is found.

— Function: **poly-simplify**` poly`

Simplify polynomial coefficient list

polyby (destructively) clipping off trailing zeros.

— Function: **poly-mix**` a ac b bc`

Mix two polynomial lists

aandb(in the form returned by`is-polynomial`

) in a linear combination with coefficient expressionsacandbc. The result is a (not necessarily simplified) polynomial list representing ‘’.aca+bcb

— Function: **poly-mul**` a b`

Multiply two polynomial coefficient lists

aandb. The result will be in simplified form if the inputs were simplified.

— Function: **build-polynomial-expr**` poly var`

Construct a Calc formula which represents the polynomial coefficient list

polyapplied to variablevar. Thea c(`calc-collect`

) command uses`is-polynomial`

to turn an expression into a coefficient list, then`build-polynomial-expr`

to turn the list back into an expression in regular form.

— Function: **check-unit-name**` var`

Check if

varis a variable which can be interpreted as a unit name. If so, return the units table entry for that unit. This will be a list whose first element is the unit name (not counting prefix characters) as a symbol and whose second element is the Calc expression which defines the unit. (Refer to the Calc sources for details on the remaining elements of this list.) Ifvaris not a variable or is not a unit name, return`nil`

.

— Function: **units-in-expr-p**` expr sub-exprs`

Return true if

exprcontains any variables which can be interpreted as units. Ifsub-exprsis`t`

, the entire expression is searched. Ifsub-exprsis`nil`

, this checks whetherexpris directly a units expression.

— Function: **single-units-in-expr-p**` expr`

Check whether

exprcontains exactly one units variable. If so, return the units table entry for the variable. Ifexprdoes not contain any units, return`nil`

. Ifexprcontains two or more units, return the symbol`wrong`

.

— Function: **to-standard-units**` expr which`

Convert units expression

exprto base units. Ifwhichis`nil`

, use Calc's native base units. Otherwise,whichcan specify a units system, which is a list of two-element lists, where the first element is a Calc base symbol name and the second is an expression to substitute for it.