This is an old revision of the document!

Symbolic expressions (formulas, equations, polynomials, etc) are enclosed in single quotes (' ') and may include any mathematically valid combination of numbers, constants, variables, functions and operators.

Examples of valid symbolic expressions are:
'X+1'
'√(X+2)/(1-z)^2'

### Working with expressions

Expressions can be manipulated in various ways:

Normal operations using the stack: 'X+1' 2 * will produce the expression '(X+1)*2' as expected. The result of operations involving expressions is always an expression. No other processing is performed, the expression remains as the user input, for example: '(X+1)*2' 2 / will produce '((X+1)*2)/2'.

Evaluating the expression: Using the commands EVAL1, EVAL and →NUM will replace the contents of any variables that exist in the current directory (or upper) or as local variables while running a program, into the expression. The behavior of each command is only slightly different:

EVAL will replace variables with their content, and if those contents include variables, it will recursively replace them as well until no more replacements are possible. Variables that are not defined remain as symbolic variables. Numerical operations will be performed as long as the result is guaranteed exact and integer, otherwise they will remain as a symbolic expression. For example 1+1/2 EVAL will result in '3/2'. After EVAL the expression is always simplified using AUTOSIMPLIFY automatically (see the command AUTOSIMPLIFY).

EVAL1 will replace variables with their contents, but will not recurse into the contents of the variables. For example assume the variable X is defined as 'X+1'. Evaluating the expression 'X+5' with EVAL would produce a circular reference error. Using EVAL1 would return 'X+6', after replacing X only one time. After EVAL1 the expression is always simplified using AUTOSIMPLIFY automatically (see the command AUTOSIMPLIFY).

→NUM will replace variables with their contents, recursively just as EVAL but it requires the final result to be numeric. If any variable is undefined it will error.

Algebraic manipulation: Expressions can be modified by a number of commands that perform changes to the structure of the expression but preserving its symbolic nature. Most of the commands that modify an expression apply a combination of algebraic rules with other algorithms to produce the result. An example of this class of commands is the AUTOSIMPLIFY command, which performs numeric operations and applies a series of simple rules.

### Algebraic Rules

Rules are expressions used to match and replace parts of an expression with other expressions, and are the base of symbolic manipulation. Rules are symbolic expressions themselves, which have a left and right parts, separated with the rule operator :→. Rules can be applied to expressions with the command RULEAPPLY and RULEAPPLY1. The difference between them is (just like EVAL and EVAL1) that RULEAPPLY will apply the rule multiple times until no more changes are produced to the expression, while RULEAPPLY1 will apply the rule only once. Both commands return the number of replacements that were performed, or zero if nothing was changed.

For example, 'X+Y+1' 'X+1:→Z' RULEAPPLY it will search into the expression 'X+Y+1' and replace every occurrence of X+1 with Z. The rules engine always assumes the + operator is commutative, therefore it will try all permutations of the terms, resulting in the expression 'Z+Y' and 1 indicating it performed one replacement.

The usefulness of rules only becomes evident when wildcards are used. Wildcards are special variable names that will match different objects. The rules engine recognizes wildcards by the 2 first characters of the variable name. All wildcards start with a dot, and the character that follows indicates what type of wildcard it is (what objects it will match). Other characters are an arbitrary name assigned by the user. In the table below the name VAR is used as an example and can be substituted freely.

Wildcard Meaning
.iVAR Match a single integer number
.oVAR Match a single odd integer number
.eVAR Match a single even integer number
.nVAR Match a single number (not necessarily an integer)
.NVAR Match the largest possible numeric sub-expression
.vVAR Match a single variable
.mVAR Match any algebraic sub-expression, use non-commutative multiplication
.xVAR Match any algebraic sub-expression
.MVAR Match the largest possible algebraic sub-expression (non-commutative multiplication)
.XVAR Match the largest possible algebraic sub-expression

For examples on the use of wildcards, let's use the expression '√3*X^2+2.5*X+5*X*Y+(A+B)*Y^2' and apply some rules to it using RULEAPPLY:

Rule Result Why?
'X^.iN:→Z^.iN' '√3*Z^2+2.5*X+5*X*Y+(A+B)*Y^2' Only the first term has the form X^i
'.vX^.iN:→Z^.iN' '√3*Z^2+2.5*X+5*X*Y+(A+B)*Z^2' The variable wildcard .vX matches both X and Y and makes 2 replacements. Because we used RULEAPPLY, it tries again and then matches Z and replaces it in 2 places, reporting 4 total changes after stopping due to the expression not changing
'.nN*.vX:→.nN*(.vX-.nN)' '√3*X^2+2.5*(X-2.5)+5*(X-5)*(Y-5)+(A+B)*Y^2' It finds 2.5*X and replaces, then finds 5*X, replaces with 5*(X-5) then on the same term finds 5*Y and replaces it with 5*(Y-5), reporting a total of 3 replacements
'.nN*.vX^2:→.nN*(.vX-1)^2' '√3*X^2+2.5*X+5*X*Y+(A+B)*Y^2' Does not make any replacements, since √3 is not a single number but a numeric expression
'.NN*.vX^2:→.NN*(.vX-1)^2' '√3*(X-1)^2+2.5*X+5*X*Y+(A+B)*Y^2' Using .NN instead, matches √3 and does the replacement
'.xN*.vX^2:→.xN*(.vX-1)^2' '√3*(X-1)^2+2.5*X+5*X*Y+(A+B)*(Y-1)^2' Using .xN instead, matches √3 and (A+B) as well
'.NN*.vX^2+.XR:→.XR' '2.5*X+5*X*Y+(A+B)*Y^2' Finds √3*X^2'+… where .XR represents the rest of the expression, and removes the term
'.xN*.vX^2+.XR:→.XR' '2.5*X+5*X*Y' Finds √3*X^2' and removes the term, then also finds (A+B)*Y^2 and removes it as well

### Attributes

Attributes are hints that the user can include in an expression to increase the knowledge that the system has about certain variables. For example, if variables A and B in the expression 'A*B*INV(A)' represent a matrix, the system should not simplify that expression to 'B'. Furthermore, if A and B are real numbers, the simplification is only valid when A is known not to be zero.

Attributes allow the user to let the system know that A is a real number and it cannot be zero. To add attributes to a variable, simply add a combination of subscript numbers after the variable name. For example, if A is a real number known not to be zero, simply write A₂₁ in the expression (the exact meaning of the numbers will be explained in the next section). Notice that these attributes are only visible when editing the expression. Once the expression is in the stack, only the name of the variable will be visible, as the subscript numbers don't become part of the name of the variable. Ideally, the user should provide the same attributes to the same variables all throughout the expression (otherwise the system will think the variable represents different things in different parts of the same expression).

Attributes are also useful within rules. If a variable (or wildcard special variable) has any attributes given within a rule definition, it will only match variables (or expressions) that have compatible attributes. For example a rule to cancel out factors in an expression could be: '.xX/.xX:→1'. But this is not correct if the expression being canceled may be zero. Using attributes, we can write '.xX₂₁/.xX₂₁:→1' and now it will only match expressions that are known to be real and are known not to be zero.

#### Default attributes

Variables that aren't given any attributes are by default assumed to be real if complex mode is disabled, and complex if complex mode is enabled. No other assumptions are made about their value (could be in any range, could be zero or infinite, etc.).

#### Encoding of attributes

Attributes can be any number of up to 8 decimal digits. The value of zero is reserved for 'no attributes' and will be automatically removed from the variables. The newRPL algebraic engine uses only 3 digits (other digits may or may not be used in the future). The first 3 digits will be referred to as 't' (for type), 's' (sign) and 'p' (parity) from now on. They go after a variable in 'tsp' order, and trailing zeros can be omitted.

The first digit provides hints about the type of variable:

First digit 't' (type):
Value Meaning
1 Variable may be infinity or NaN
2 Variable is known to be real
3 Variable is known to be real, may be infinity/NaN
4 Variable is known to be complex
5 Variable is known to be complex, may be infinity/NaN
6 Variable is known to be a matrix
8 2) Variable is known to be of unknown type

The second digit provides insight about the sign and range of values. It is meaningful only for real numbers (except for the zero hint), other types don't need or use this digit.

Second digit 's' (sign):
Value Meaning
0 3) Nothing is known about the sign or range of this value
1 Value is known not to be zero 4)
2 Value is known not to be < 0 (therefore it's >=0)
3 Value is known not to be < 0 and not to be zero (therefore it's >0)
4 Value is known not to be > 0 (therefore it's ⇐0)
5 Value is known not to be > 0 and not to be zero (therefore it's <0)

^ Third digit 'p' (parity): ||

 Value Meaning 0 5) Nothing is known regarding parity of this value 1 Value if known to be an integer 2 Value is known to be odd 3 Value is known to be an odd integer 4 Value is known to be even 5 Value is known to be an even integer

1)
Will be automatically removed
2)
Internal use only
3) , 5)
Will be removed/omitted
4)
This is valid for real AND complex numbers
• manual/chapter3/symbolic.1548348373.txt.gz