Go forward to Formatting Lisp Functions.
Go backward to Vector Lisp Functions.
Go up to Internals.
Symbolic Functions
..................
The functions described here operate on symbolic formulas in the
Calculator.
-- Function: calc-prepare-selection NUM
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 variables. `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 `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
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.
-- Function: calc-encase-atoms X
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.
-- 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 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 `calc-find-nth-part' with N equal to four
will return `d'.
-- Function: calc-find-parent-formula EXPR PART
Return the sub-formula of EXPR which immediately contains PART.
If EXPR is `a*b + (c+1)*d' and PART is `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 `nil'.
If PART is `eq' to EXPR, 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
(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', `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 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.
-- Function: calc-find-sub-formula EXPR 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 `nil'. If PART is `eq' to EXPR, 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' to OLD replaced by NEW.
-- Function: simplify EXPR
Simplify the expression EXPR by applying various algebraic rules.
This is what the `a s' (`calc-simplify') command uses. 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
`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 when X is 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'. If FUNCS is a symbol
(like `+' or `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 executed with `expr' bound to a formula which is a
call to one of the functions FUNCS. 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 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 `simplify' loop.
Note that, since `defmath' is not being used here, BODY must be
written in true Lisp code without the conveniences that `defmath'
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
`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 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
`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 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)))))))
-- Function: frac-gcd A B
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.
-- Function: map-tree FUNC EXPR MANY
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 `equal' to 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.
-- 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 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.
-- Function: rewrite-heads EXPR
Compute a HEADS list for EXPR suitable 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
throughout EXPR up to MANY (default infinity) times.
-- Function: match-patterns PAT VEC NOT-FLAG
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 non-`nil')
match any of the patterns in PAT.
-- Function: deriv EXPR VAR VALUE SYMB
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 undifferentiable functions in EXPR instead cancels
the whole differentiation, and `deriv' returns `nil' instead.
Derivatives of an N-argument function can be defined by adding a
`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 `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 than VAR are not assumed to
be constant with respect to VAR.
-- Function: integ EXPR VAR LOW HIGH
Compute the integral of EXPR with respect to VAR.
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 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
`math-integ-var'. If 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))))
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 that BODY is written as the body of a function with two
arguments, U and V.
-- Function: solve-for LHS RHS VAR FULL
Attempt to solve the equation `LHS = RHS' by isolating the
variable VAR on the lefthand side; return the resulting righthand
side, or `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 `solve' and `finv' functions, 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.
-- 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 `EXPR = 0'.) It returns an
equation or inequality, or `nil' if no solution could be found.
-- Function: solve-system EXPRS VARS FULL
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.
-- Function: expr-contains EXPR VAR
Returns a non-`nil' value if VAR occurs as a subexpression of
EXPR.
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 VAR as a subexpression of
EXPR, or `nil' if there are no occurrences.
-- Function: expr-depends EXPR VAR
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.
-- Function: expr-contains-vars EXPR
Return true if EXPR contains any variables, or `nil' if EXPR
contains only constants and functions with constant arguments.
-- Function: expr-subst EXPR OLD NEW
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.
-- Function: multi-subst EXPR 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 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 in EXPR. 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 `A + B' counts as a
function call.) For primitive objects, this returns zero.
-- Function: polynomial-p EXPR VAR
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.
-- Function: is-polynomial EXPR VAR DEGREE LOOSE
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 `nil' 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.
-- Function: polynomial-base EXPR PRED
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 is found.
-- Function: poly-simplify POLY
Simplify polynomial coefficient list POLY by (destructively)
clipping off trailing zeros.
-- Function: poly-mix A AC B BC
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'.
-- Function: poly-mul A B
Multiply two polynomial coefficient lists A and B. 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 POLY applied to variable VAR. The `a 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 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 `nil'.
-- Function: units-in-expr-p EXPR SUB-EXPRS
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 `nil', this checks whether EXPR is
directly a units expression.
-- Function: single-units-in-expr-p EXPR
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 `wrong'.
-- Function: to-standard-units EXPR WHICH
Convert units expression EXPR to base units. If WHICH is `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.
-- Function: remove-units EXPR
Return a copy of EXPR with all units variables replaced by ones.
This expression is generally normalized before use.
-- Function: extract-units EXPR
Return a copy of EXPR with everything but units variables
replaced by ones.