The functions described here operate on symbolic formulas in the Calculator.
Prepare a stack entry for selection operations. If num is
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
calc-selection-cache-num contains the number of
the stack entry involved (equal to num if you specified it);
calc-selection-cache-entry contains the stack entry as a
list (such as
calc-top-list would return with
as the selection mode); and
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 n 0)’. This list will be displayed the same as a
plain n and 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.
This modifies the formula x to ensure that each part of the
formula is a unique atom, using the ‘(cplx n 0)’ trick
described above. This function may use
setcar to modify
the formula in-place.
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
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.
Return the nth sub-formula of expr. This function is used
by the selection commands, and (unless j b has been used) treats
sums and products as flat many-element formulas. Thus if expr
is ‘((a + b) - c) + d’, calling
n equal to four will return ‘d’.
Return the sub-formula of expr which immediately contains
part. If expr is ‘a*b + (c+1)*d’ and part
eq to the ‘c+1’ term of expr, then this function
will return ‘(c+1)*d’. If part turns out not to be a
sub-formula of expr, the function returns
eq to expr, the function returns
This function does not take associativity into account.
This is the same as
calc-find-parent-formula, except that
(unless j b has been used) it continues widening the selection
to contain a complete level of the formula. Given ‘a’ from
‘((a + b) - c) + d’,
return ‘a + b’ but
return the whole expression.
This expands sub-formula part of expr to encompass a complete level of the formula. If part and its immediate parent are not compatible associative operators, or if j b has been used, this simply returns part.
This finds the immediate sub-formula of expr which contains
part. It returns an index n such that
‘(calc-find-nth-part expr n)’ would return part.
If part is not a sub-formula of expr, it returns
If part is
eq to expr, it returns
function does not take associativity into account.
This function returns a copy of formula expr, with the
sub-formula that is
eq to old replaced by new.
Simplify the expression expr by applying Calc’s algebraic simplifications. This always returns a copy of the expression; the structure expr points 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
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.
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 when x is positive.) This is
implemented by temporarily binding the variable
t (using a
let form) and calling
Dangerous simplification rules are written to check this variable
before taking any action.
Simplify the expression expr, treating variable names as units
whenever possible. This works by binding the variable
t while calling
Register a new simplification rule; this is normally called as a top-level
defmath. If funcs is a symbol
calcFunc-sqrt), this simplification rule is
applied to the formulas which are calls to the specified function. Or,
funcs can be a list of such symbols; the rule applies to all
functions on the list. The body is written like the body of a
function with a single argument called
expr. The body will be
expr bound to a formula which is a call to one of
the functions funcs. If the function body returns
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 for expr in 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
Note that, since
defmath is not being used here, body must
be written in true Lisp code without the conveniences that
provides. If you prefer, you can have body simply 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
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’.
Check expr to see if it is a sum of terms all multiplied by the
same rational value. If so, return this value. If not, return
For example, if called on ‘6x + 9y + 12z’, it would return 3, since
3 is a common factor of all the terms.
Assuming expr is a sum with factor as a common factor, divide each term of the sum by factor. This is done by destructively modifying parts of expr, 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)))))))
Compute a “rational GCD” of a and b, which must both be
rational numbers. This is the fraction composed of the GCD of the
numerators of a and b, 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.
Try applying Lisp function func to various sub-expressions of
expr. Initially, call func with expr itself as an
argument. If this returns an expression which is not
expr, apply func again until eventually it does return
expr with no changes. Then, if expr is a function call,
recursively apply func to 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,
func functions may not make destructive changes to
expr. If a third argument many is provided, it is an
integer which says how many times func may be applied; the
default, as described above, is infinitely many times.
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
for that same variable can return immediately. If there are problems
with the rules, this function calls
error with a suitable
Apply the compiled rewrite rule set crules to the expression
expr. 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. The heads argument is optional; if is given,
it should be a list of all function names that (may) appear in
expr. The rewrite compiler tags each rule with the
rarest-looking function name in the rule; if you specify heads,
apply-rewrites can use this information to narrow its search
down to just a few rules in the rule set.
Compute a heads list for expr suitable for use with
apply-rewrites, as discussed above.
This is an all-in-one rewrite function. It compiles the rule set
specified by rules, then uses
map-tree to apply the
rules throughout expr up to many (default infinity)
Given a Calc vector vec and an uncompiled pattern set or
pattern set variable pat, this function returns a new vector
of all elements of vec which do (or don’t, if not-flag is
nil) match any of the patterns in pat.
Compute the derivative of expr with respect to variable var
(which may actually be any sub-expression). If value is specified,
the derivative is evaluated at the value of var; otherwise, the
derivative is left in terms of var. 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, if symb is non-
nil, the presence of nondifferentiable
functions in expr instead cancels the whole differentiation, and
Derivatives of an n-argument function can be defined by
math-derivative-n property 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
is defined by
(put 'calcFunc-ln\' 'math-derivative-1 (function (lambda (u) (math-div 1 u))))
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) ... )))
Compute the total derivative of expr. This is the same as
deriv, except that variables other than var are not
assumed to be constant with respect to var.
Compute the integral of expr with respect to var. See Calculus, for further details.
Define a rule for integrating a function or functions of one argument;
this macro is very similar in format to
The main difference is that here body is 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
evaluation of the integral requires doing further integrals, the body
should call ‘(math-integral x)’ to find the integral of
x with 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))))
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-
Define a rule for integrating a function or functions of two arguments.
This is exactly analogous to
math-defintegral, except that body
is written as the body of a function with two arguments, u and
Attempt to solve the equation ‘lhs = rhs’ by isolating
the variable var on the lefthand side; return the resulting righthand
nil if the equation cannot be solved. The variable
var must appear at least once in lhs or rhs. Note that
the return value is a formula which does not contain var; this is
different from the user-level
which return a rearranged equation or a functional inverse, respectively.
If full is 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 x)’ to create a new arbitrary sign variable, returning x times that sign, and ‘(math-solve-get-int x)’ to create a new arbitrary integer variable multiplied by x. These functions simply return x if the caller requested a non-“full” solution.
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 ‘expr = 0’.) It returns an
equation or inequality, or
nil if no solution could be found.
This function solves a system of equations. Generally, exprs and vars will be vectors of equal length. See Solving Systems of Equations, for other options.
Returns a non-
nil value if var occurs as a subexpression
This function might seem at first to be identical to
calc-find-sub-formula. The key difference is that
equal to test for matches, whereas
eq. In the formula
‘f(a, a)’, the two ‘a’s will be
equal but not
eq to each other.
Returns the number of occurrences of var as a subexpression
of expr, or
nil if there are no occurrences.
Returns true if expr refers to any variable the occurs in var. In other words, it checks if expr and var have any variables in common.
Return true if expr contains any variables, or
nil if expr
contains only constants and functions with constant arguments.
Returns a copy of expr, with all occurrences of old replaced
by new. This treats
lambda forms specially with respect
to the dummy argument variables, so that the effect is always to return
expr evaluated at old = new.
This is like
expr-subst, except that old and new
are lists of expressions to be substituted simultaneously. If one
list is shorter than the other, trailing elements of the longer list
Returns the “weight” of expr, basically a count of the total number of objects and function calls that appear in expr. For “primitive” objects, this will be one.
Returns the “height” of expr, which is the deepest level to which function calls are nested. (Note that ‘a + b’ counts as a function call.) For primitive objects, this returns zero.
Check if expr is a polynomial in variable (or sub-expression)
var. If so, return the degree of the polynomial, that is, the
highest power of var that appears in expr. For example,
for ‘(x^2 + 3)^3 + 4’ this would return 6. This function returns
nil unless expr, when expanded out by a x
calc-expand), would consist of a sum of terms in which var
appears only raised to nonnegative integer powers. Note that if
var does not occur in expr, then expr is considered
a polynomial of degree 0.
Check if expr is a polynomial in variable or sub-expression
var, and, if so, return a list representation of the polynomial
where the elements of the list are coefficients of successive powers of
var: ‘a + b x + c x^3’ would produce the
list ‘(a b 0 c)’, and ‘(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 if expr is the
constant zero, the returned value will be ‘(0)’. Return
if expr is not a polynomial in var. If degree is
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. If
loose is non-
nil, then a looser definition of a polynomial
is used in which coefficients are no longer required not to depend on
var, 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.
Check if expr is a polynomial in any variable that occurs in it;
if so, return that variable. (If expr is a multivariate polynomial,
this chooses one variable arbitrarily.) If pred is specified, it should
be a Lisp function which is called as ‘(pred subexpr)’,
and which should return true if
mpb-top-expr (a global name for
the original expr) is a suitable polynomial in subexpr.
The default predicate uses ‘(polynomial-p mpb-top-expr subexpr)’;
you can use pred to specify additional conditions. Or, you could
have pred build up a list of every suitable subexpr that
Simplify polynomial coefficient list poly by (destructively) clipping off trailing zeros.
Mix two polynomial lists a and b (in the form returned by
is-polynomial) in a linear combination with coefficient expressions
ac and bc. The result is a (not necessarily simplified)
polynomial list representing ‘ac a + bc b’.
Multiply two polynomial coefficient lists a and b. The result will be in simplified form if the inputs were simplified.
Construct a Calc formula which represents the polynomial coefficient
list poly applied to variable var. The a c
calc-collect) command uses
is-polynomial to turn an
expression into a coefficient list, then
to turn the list back into an expression in regular form.
Check if var is 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.) If var
is not a variable or is not a unit name, return
Return true if expr contains any variables which can be
interpreted as units. If sub-exprs is
t, the entire
expression is searched. If sub-exprs is
checks whether expr is directly a units expression.
Check whether expr contains exactly one units variable. If so,
return the units table entry for the variable. If expr does
not contain any units, return
nil. If expr contains
two or more units, return the symbol
Convert units expression expr to base units. If which
nil, use Calc’s native base units. Otherwise, which
can 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.
Return a copy of expr with all units variables replaced by ones. This expression is generally normalized before use.
Return a copy of expr with everything but units variables replaced by ones.