====================================================================
OrderedFreeMonoid examples
====================================================================

m1:=(x*y*y*z)$OFMONOID(Symbol)

m2:=(x*y)$OFMONOID(Symbol)

lquo(m1,m2)

m3:=(y*y)$OFMONOID(Symbol)

div(m1,m2)

div(m1,m3)

m4:=(y^3)$OFMONOID(Symbol)

div(m1,m4)

Build the non-commutative algebra h=k[x,y] and then make computations
in h using some predefined rules for x and y. For example, giving

   x*y*x=y*x*y
   x*x=a*x+b
   y*y=a*y+b

where a dn b are generic elements of k.

Then reduce the polynomials in x and y according to the previous rules.
That is, given

   (x+y)^2   ( = x^2+x*y+y*x+y^2)

should reduce to

   a*(x+y)+2*b+x*y+y*x

We can reduce the clutter of the work by defining macros for the types
of the domains we need to create. So first we create those macros.

We create generic elements of k. First we define a macro for the domain of
ordered variables (OVAR is OrderedVariableList)

  C ==> OVAR [a,b]

Next we define a macro for the commutative field domain k = Q[a,b]
where Q is Fraction(Integer) and SMP is SparseMultivariatePolynomials

  K ==> SMP(FRAC INT,C)

Now we need some non-commutative variables so we create a macro for that.

  V ==> OVAR [x,y]

And now we need to define the non-commuative algebra k=k[x,y].
We use the domain XDistributedPolynomial (XDPOLY) as a macro.

  H ==> XDPOLY(V,K)

The non-commutative variables are in an Ordered Free Monoid

  M ==> OFMONOID V

We have three rules to apply. So we create a function that examines one
term. Substitution rules are applied to words from the monoid over the 
variables and retun polynomials. If any rule matches we construct the
substitution, create a new monomial term and return it.

  subs(w:M):H ==
    -- x*y*x = y*x*y
    n1:=lquo(w,(x::V*y::V*x::V)$M)$M
    n1 case "failed" => monom(w,1)$H
        -- x*x = a*x+b
      n2:=lquo(w,(x::V^2)$M)$M
      n2 case "failed" => monom(w,1)$H
        -- y*y = a*y+b
        n3:lquo(w,(y::V^2)$M)$M
        n3 case "failed" => monom(w,1)$H
        monom(n3,1)$H * (a::K*y::V+b::K)$M * monom(n3,1)$H
      monom(n2,1)$H * (a::K*x::V+b::K)$H * monom(n2,1)$H
    monom(n1,1)$H * (y::V*x::V*y::V)$H * monom(n1,1)$H

We apply these rules to a term, remembering the coefficient

  newterm(x:Record(k:M,c:K)):H == x.c*subs(x,k)


And now we create a function to reconstruct the polynomial term by term.

  newpoly(t:H):H == reduce(+,map(newterm,listOfTerms(t)))


For example,

  p1:(x::V+y::V)$H^2

  newpoly(p1)

  p2:=(x::V+y::V)$H^3

  pNew:=newpoly(p2)

But the rules should be applied more than once so we create a function
to iterate the rules until nothing changes.

  reduce(p:H):H ==
    p2 := newpoly(p)
    p3 := newpoly(p2)
    while p3 ~= p2 repeat
      p2 := p3
      p3 := newpoly(p2)
    p3

And we can see it work

  reduce(p2)

See Also:
o )show OrderedFreeMonoid

