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: 0This 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: 1Applies the rule
fe.assgnrule.ruleto 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: 2Applies the rule
fe.assgnrule.ruleto fe.expr. This rule is an instancefe.prerule, index: 3Applies the rule assigned to the attribute
fe.prerule.ruleto fe.expr. This rule can be reassigned. The prefix ‘pre’ indicates fe.prerule is executed before fe.eventrule.fe.eventrule, index: 4During 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: 5Applies the rule assigned to the attribute
fe.postrule.ruleto fe.expr. This rule can be reassigned. The prefix ‘post’ indicates fe.prerule is executed after fe.eventrule.
fe.historyupdate, index: 6The list fe.history is updated (appended) with fe.expr
fe.assignupdate, index: 7If fe.expr is an Assign expression with two items, The dictionary fe.assigneddict is updted.
fe.naturalupdate, index: 8If 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.
fe.print, index: 9The expression fe.expr is printed.
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.
Print Action
The fe.print action prints the final expression fe.expr.
But as demostared below, The frontend __call__ method result is None.
In [2]: frontend_result = fe(' cos(x) ')
Ex(0): cos(x)
In [3]: frontend_result is None
Out[3]: True
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:
A Container instance with name ‘Ex’. (The name can be set to something else)
There is only one item in the items atttribute. That item is a Number instance.
The value attribute of the Number object must be an integer.
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.
forallfunctionis the first Rule argument that identifies variables used within the matching process for a NatualRule. A
forallfunction 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