Frontend

The FrontEnd class is developed in the module truealgebra.core.frontend. In the import section above, the name cas.fe refers to a FrontEnd instance. When a frontend is called, it takes a python string as a positional argument. That string represents a mathematical expression and is parsed into a TrueAlgebra expression. Then, depending on particular details of the frontend, TrueAlgebra rules csn be applied to the parsed expression and other operstions occur..

A frontend is the user interface tool for TrueAlgebra. It provides a platform for the user to create TrueAlgebra expressions from python strings that represent mathematical expressions. The frontend also provides the means to create and apply TrueAlgebra rules to these expressions. Users have access to and can use the history of TrueAlgebra expressions previously created and transformed.

The frontend was designed for use in an interactive environment such as ipython. The frontend __call__ method is defined and frontend acts like a function. A user can make a frontend call, then observe the consequences of that call then repeat the process for as long as needed.

The use of a frontend will become a session of a series of user actions and the frontend response.

Import below from truealgebra.tasympy to get the tasymp CAS (Computer Algebra System).

In [1]: from truealgebra import tasympy as cas
   ...: cas.setup_func()
   ...: fe = cas.create_frontend()
   ...: Ex = fe.history
   ...: 

Above, the shorter name fe was defined for frontend. It is highly desirable to have a very short name for the frontend, as the name will be typed often in a TrueAlgebra session.

Frontend Event

An event is defined here as what happens when cas.frontend or the much shorter name fe is called with a python string as its first positional argument. That string represents a mathematical expression and is parsed into TrueAlgebra expression and stored into frontend.expr.

The attribute fe.actions is a list of Action class instances called here an action. The action attribute of every action in fe.actions is executed. Below is a brief description of what each action does and the order they occur.

fe.historyrule, index: 0

This action apples the rule fe.historyrule.rule to fe.expr. The rule is a truealgebra.core.frontend.HistoryRule object. The rule can substitute expressions from fe.history into fe.expr.

fe.assignrule, index: 1

Applies the rule fe.assgnrule.rule to fe.expr. This rule is an instance of truealgebra.core.frontend.ssignRule and makes substitutions into fe.expr using the dictionary fe.assigndict as a map.

fe.naturalrule, index: 2

Applies the rule fe.assgnrule.rule to fe.expr. This rule is an instance

fe.prerule, index: 3

Applies the rule assigned to the attribute fe.prerule.rule to fe.expr. This rule can be reassigned. The prefix ‘pre’ indicates fe.prerule is executed before fe.eventrule.

fe.eventrule, index: 4

During an frontend event, all ssstatic arguments after the first string arguments for the fe.__call__ method are stored in order in fe.rules. The fe.eventrule action applies the rules in fe.rules to fe.expr

Note that in every event, the fe.rules attribute is reassigned before any actions are executed.

fe.postrule, index: 5

Applies the rule assigned to the attribute fe.postrule.rule to fe.expr. This rule can be reassigned. The prefix ‘post’ indicates fe.prerule is executed after fe.eventrule.

fe.historyupdate, index: 6

The list fe.history is updated (appended) with fe.expr

fe.assignupdate, index: 7

If fe.expr is an Assign expression with two items, The dictionary fe.assigneddict is updted.

fe.naturalupdate, index: 8

If fe.expr is a Restricted expression with the name “Rule”, and is formatted correctly, a NaturalRule instances is created and stored into the list fe.naturalrules.

The above description is specific to the FrontEnd instance fe. However the the process of creating an FrontEnd instqnce is very extendable. The actions iand thier order can be adjusted as needed and new Action and FrontEnd subclasses created to generate customized frontends for partictular purposes.

History

The frontend histoty is the list fe.history which contains the final expression fe.expr for each event. The history can be thought of as a list of outputs from each event. Below, the first item in the history list is the expression from the above event. The fe.historyupate action appends the event’s fe.expr to the history list.

In [4]: print('history=  ', fe.history)
history=   [cos(x)]

The fe.historyrule applies a rule to fe.expr makes subsitutes into subexpressions that meet the floowing criteria:

  1. A Container instance with name ‘Ex’. (The name can be set to something else)

  2. There is only one item in the items atttribute. That item is a Number instance.

  3. The value attribute of the Number object must be an integer.

  4. The integer must be in the range of acceptable indexes for the history list.

When the above conditions are met, the rule substitutes the appropriate expression in the history rule. For example:

#fe(' f(Ex(0), Ex(-1)) ')

The fe.historyrule action Now use the history rule

When the history rule will ignore all Container expressions with inappropiate indexs. Consider the example below.

The history rule insert Items in the The fe.history list into the frontend expression being modified. In the frontend expression, sub-expressions of the form Ex(n) where n is an integer are replaced by the expression in history at index n . Consider the example:

In [5]: fe('  f(Ex(1.3), Ex(-1000), Ex(1000), Ex(junk)) ')
Ex(1):    f(Ex(1.30000000000000), Ex(-1000), Ex(1000), Ex(junk))

The history rule ignres entire expreeion. The first index of Ex is a Float number. The next two indexs are integers but are out of range. The index of the last Ex(junk) is parsed as a Symbol object.

AssignRule Actions

Assign Expression

An assign expression is a truealgebras expression of the form <lhs> := <rhs> where <lhs> and <rhs> are any truealgebra expressions. The left hand side <lhs> is usually a truealgebra Symbol instance. A assign expression means that <rhs> is assigned to <lhs>.

The := infix operator is a definition of assignment. It does not represent mathemetical equality: https://math.stackexchange.com/questions/25214/what-does-mean.

An assign expression is a Assign class instance and its left hand side <lhs> argument will not be accessed by rules applied bottomup. The <lhs> will only be altered by rules specifically designed to do so. Most rules will not alter the left hand side of a assign function.

AssignUpdate

The fe.assignupdate action updates the attribute fe.assigndict when fe.expr is an assign expression: fe.assigndict[<lhs>] = <rhs>.

As an example, fe.assigndict is initially empty. The symbol y is assigned to the symbol x. The number 2 is assigned to the symbol y, and the expresion g(x) is assigned to the expression f(z).

In [6]: fe.assigndict
Out[6]: {}

In [7]: fe(' x := a ; y := 2; f(z) := g(x) ')
Ex(2):    x := a; y := 2; f(z) := g(x)

In [8]: fe.assigndict
Out[8]: {x: a, y: 2, f(z): g(x)}

AssignRule

The AssignRule action has an attribute fe.assignrule.rule that makes substitutions based on the dictionary fe.assigndict. For example:

In [9]: fe('  func0(x) + func0(1) + f(z)  ')
Ex(3):    func0(a) + func0(1) + g(x)

Remap Assigndict Keys

When the left hand side argument of an assign function is the same as a key in fe.assigndict, The value related to the key will become the right hand side argument as seen below.

In [10]: fe('  x := w  ')
Ex(4):    x := w

In [11]: fe.assigndict
Out[11]: {x: w, y: 2, f(z): g(x)}

Modify Assign Expression

The right hand side <rhs> in a assign expression can be modified by rules inside a frontend event. The assignupdate action action has index 7, and is applied after all the frontend actions that apply rules.

As an example calculate the volume of a cuboid First assign numbers to the height, width, and depth symbols.

In [12]: fe(' height := 2.0; width := 3.0; depth := 4.0 ')
Ex(5):    height := 2.00000000000000; width := 3.00000000000000; depth := 4.00000000000000

In [13]: fe.assigndict
Out[13]: 
{x: w,
 y: 2,
 f(z): g(x),
 height: 2.00000000000000,
 width: 3.00000000000000,
 depth: 4.00000000000000}

Next calculate the volume using a formula.

In [14]: fe(' volume := height * width * depth ')
Ex(6):    volume := 2.00000000000000 * 3.00000000000000 * 4.00000000000000

In [15]: fe.assigndict
Out[15]: 
{x: w,
 y: 2,
 f(z): g(x),
 height: 2.00000000000000,
 width: 3.00000000000000,
 depth: 4.00000000000000,
 volume: *(2.00000000000000, *(3.00000000000000, 4.00000000000000))}

What happened inside the previous frontend event is after parsing``fe.expr`` was volume := height * width * depth. The assignrule action converted fe.expr to volume := 2.0 * 3.0 * 4.0. Then the fe.prerule action converted fe.expr to volume := 24.0. Then fe.assignupdate updates fe.assigndict.

Frontend Naturalrule

The naturalruleupdate action allows a user to create NaturalRule instances within a frontend session. The outcome_rule is set to the default donothing_rule, which does nothing. The NaturalRule predicate_rule attribute is set to sympy.predicate_rule_bu.

the naturalruleupdate action creates a NaturalRule instance from the three arguments of a Rule function in the frontend expression.

forall function

is the first Rule argument that identifies variables used within the matching process for a NatualRule. A forall function can contain suchthat functions that specify predicate expressions that a variable must satisfy.

pattern expression

is the second Rule argument. It is the pattern that must be matched for the rule to be applied.

outcome expression

is the third Rule argument. When a match is found, the outcome expression replaces the input expression.

Consider the example below.

In [16]: fe(' Rule('
   ....:     'forall(x, y suchthat isrational(y) and y > 1/2),'
   ....:     'f(x, y),'
   ....:     'g(x, y)'
   ....: ')' )
   ....: 
Ex(7):    Rule(forall(x, y suchthat isrational(y) and y > 1/2), f(x, y), g(x, y))

Blah blah

In [17]: fe(' f(3.5, 2/3) ')
Ex(8):    g(3.50000000000000, 2/3)
In [18]: fe(' Rule(forall(theta), cos(theta)**2, 1 - sin(theta)**2) ')
Ex(9):    Rule(forall(theta), cos(theta) ** 2, 1 - sin(theta) ** 2)

When any expression matches the pattern, it is replaced by the outcome In the first example below, the symbol z matches the vatiable theta in the Rule pattern. In the second example, the expression cosh(w) ** 1.5 mathches the variable theta` in the Rule pattern.

In [19]: fe(' cos(z)**2 ')
Ex(10):    1 - sin(z) ** 2

In [20]: fe(' cos(cosh(w)**1.5)**2 ')
Ex(11):    1 - sin(cosh(w) ** 1.50000000000000) ** 2