| Title: | The Free Algebra |
|---|---|
| Description: | The free algebra in R with non-commuting indeterminates. Uses 'disordR' discipline (Hankin, 2022, <doi:10.48550/ARXIV.2210.03856>). To cite the package in publications please use Hankin (2022) <doi:10.48550/ARXIV.2211.04002>. |
| Authors: | Robin K. S. Hankin [aut, cre] (ORCID: <https://orcid.org/0000-0001-5982-0415>) |
| Maintainer: | Robin K. S. Hankin <[email protected]> |
| License: | GPL (>= 2) |
| Version: | 1.2-2 |
| Built: | 2026-05-29 09:49:51 UTC |
| Source: | https://github.com/robinhankin/freealg |
The free algebra in R with non-commuting indeterminates. Uses 'disordR' discipline (Hankin, 2022, <doi:10.48550/ARXIV.2210.03856>). To cite the package in publications please use Hankin (2022) <doi:10.48550/ARXIV.2211.04002>.
The DESCRIPTION file:
| Package: | freealg |
| Type: | Package |
| Title: | The Free Algebra |
| Version: | 1.2-2 |
| Authors@R: | person(given=c("Robin", "K. S."), family="Hankin", role = c("aut","cre"), email="[email protected]", comment = c(ORCID = "0000-0001-5982-0415")) |
| Maintainer: | Robin K. S. Hankin <[email protected]> |
| Depends: | R (>= 4.2) |
| Description: | The free algebra in R with non-commuting indeterminates. Uses 'disordR' discipline (Hankin, 2022, <doi:10.48550/ARXIV.2210.03856>). To cite the package in publications please use Hankin (2022) <doi:10.48550/ARXIV.2211.04002>. |
| License: | GPL (>= 2) |
| LazyData: | yes |
| Imports: | Rcpp (>= 1.0-7), partitions (>= 1.9-22), disordR (>= 0.9-5-1), methods |
| LinkingTo: | Rcpp |
| Suggests: | knitr, testthat, magrittr, markdown, rmarkdown, covr |
| VignetteBuilder: | knitr |
| URL: | https://github.com/RobinHankin/freealg, https://robinhankin.github.io/freealg/ |
| BugReports: | https://github.com/RobinHankin/freealg/issues |
| RoxygenNote: | 7.3.3 |
| Encoding: | UTF-8 |
| Config/pak/sysreqs: | libgmp3-dev |
| Repository: | https://robinhankin.r-universe.dev |
| Date/Publication: | 2026-05-29 07:19:04 UTC |
| RemoteUrl: | https://github.com/robinhankin/freealg |
| RemoteRef: | HEAD |
| RemoteSha: | 078f007b3fb560b624cdfe8df8771bc565d88060 |
| Author: | Robin K. S. Hankin [aut, cre] (ORCID: <https://orcid.org/0000-0001-5982-0415>) |
Index of help topics:
abelianize Abelianize a 'freealg' object
accessor Accessor methods for freealg objects
adjoint The adjoint map
constant The constant term
deriv Differentiation of 'freealg' objects
dot-class Class "dot"
drop Drop redundant information
freealg The free algebra
freealg-class Class "freealg"
freealg-package The Free Algebra
grade The grade (or degree) of terms in a 'freealg'
object
horner Horner's method
inverse Inverses
letters Single-letter symbols
linear Simple free algebra objects
nterms Number of terms in a freealg object
Ops.freealg Arithmetic Ops methods for the the free algebra
pepper Combine variables in every possible order
print.freealg Print freealg objects
rfalg Random free algebra objects
subs Substitution
zero The zero algebraic object
Robin K. S. Hankin [aut, cre] (ORCID: <https://orcid.org/0000-0001-5982-0415>)
Maintainer: Robin K. S. Hankin <[email protected]>
a <- as.freealg("x+xyx") b <- as.freealg("4x +XyX") # upper-case interpreted as inverse a+b stopifnot(a+b == b+a) # should be TRUE a*b == b*a # FALSE; noncommutative algebra as.freealg("1+X+xy")^3 rfalg() rfalg()^2a <- as.freealg("x+xyx") b <- as.freealg("4x +XyX") # upper-case interpreted as inverse a+b stopifnot(a+b == b+a) # should be TRUE a*b == b*a # FALSE; noncommutative algebra as.freealg("1+X+xy")^3 rfalg() rfalg()^2
freealg objectFunction abelianize() returns a freealg object that is
equivalent to its argument under assumption of Abelianness. The symbols
are placed in alphabetical order.
abelianize(x)abelianize(x)
x |
A |
Abelianizing a free group element means that the symbols can commute past one another. Abelianization is vectorized.
Returns an object of class freealg.
There is a very similar function in the freegroup package. However, the frab package is the best way to work with the free Abelian group.
Robin K. S. Hankin
abelianize(as.freealg("ba + 2abbba + 3abAB")) abelianize(.[rfalg(), rfalg()])abelianize(as.freealg("ba + 2abbba + 3abAB")) abelianize(.[rfalg(), rfalg()])
Accessor methods for free algebra objects
words(x) coeffs(x, drop=TRUE) coeffs(x) <- valuewords(x) coeffs(x, drop=TRUE) coeffs(x) <- value
x |
Object of class |
value |
Numeric vector of length 1 |
drop |
Boolean, with default |
Access or set the different parts of a freealg object. The
constant term is technically a coefficient but is documented under
constant.Rd.
“Pure” extraction and replacement (as in a[i] and
a[i] <- value is implemented experimentally. The code for
extraction is cute but not particularly efficient.
There is an extended discussion of disordR discipline in the
context of algebras in the mvp package at accessor.Rd.
Robin K. S. Hankin
a <- rfalg() a coeffs(a) words(a) # NB: hash is identical to that of coeffs(a) coeffs(a) <- 7 # replacement methods work a coeffs(a)a <- rfalg() a coeffs(a) words(a) # NB: hash is identical to that of coeffs(a) coeffs(a) <- 7 # replacement methods work a coeffs(a)
The adjoint of is a map from a
Lie group to the endomorphism group of defined
by
ad(x)ad(x)
x |
Object nominally of class |
Vignette adjoint gives more description
Robin K. S. Hankin
x <- rfalg() y <- rfalg() f <- ad(x) f(y) f(f(y)) # [x, [x, y]]x <- rfalg() y <- rfalg() f <- ad(x) f(y) f(f(y)) # [x, [x, y]]
Get and set the constant term of a freealg object
## S3 method for class 'freealg' constant(x) ## S3 method for class 'numeric' constant(x) ## S3 replacement method for class 'freealg' constant(x) <- value is.constant(x)## S3 method for class 'freealg' constant(x) ## S3 method for class 'numeric' constant(x) ## S3 replacement method for class 'freealg' constant(x) <- value is.constant(x)
x |
Object of class |
value |
Scalar value for the constant |
The constant term in a free algebra object is the coefficient of the
empty term. In a freealg object, the map including
implies that is
the constant.
If x is a freealg object, constant(x) returns
the value of the constant in the multivariate polynomial; if x
is numeric, it returns a constant freealg object with value
x.
Function is.constant() returns TRUE if its argument has
no variables and FALSE otherwise.
Setting the coefficients of the empty freealg returns the zero
(empty) object.
Robin K. S. Hankin
p <- as.freealg("1+X+Y+xy") constant(p) constant(p^5) constant(p) <- 1000 pp <- as.freealg("1+X+Y+xy") constant(p) constant(p^5) constant(p) <- 1000 p
freealg objectsDifferentiation of freealg objects
## S3 method for class 'freealg' deriv(x, r, ...)## S3 method for class 'freealg' deriv(x, r, ...)
x |
Object of class |
r |
Integer vector. Elements denote variables to differentiate
with respect to. If |
... |
Further arguments, currently ignored |
Experimental function deriv(S,v) returns ,
where is v[i]. The Leibniz product rule
operates even if (as here) do not commute. For example, if
we wish to differentiate with respect to , we would
write and then
and working to first order we have
In the package:
> deriv(as.freealg("aaba"),"a")
free algebra element algebraically equal to
+ 1*aab(da) + 1*a(da)ba + 1*(da)aba
A term of a freealg object can include negative values which
correspond to negative powers of variables. Thus:
> deriv(as.freealg("AAAA"),"a")
free algebra element algebraically equal to
- 1*AAAA(da)A - 1*AAA(da)AA - 1*AA(da)AAA - 1*A(da)AAAA
(see also the examples). Vector r may include negative
integers which mean to differentiate with respect to the inverse of
the variable:
> deriv(as.freealg("3abcbCC"),"C")
free algebra element algebraically equal to
+ 3*abcbC(dC) + 3*abcb(dC)C - 3*abc(dC)cbCC
It is possible to perform repeated differentiation by passing a
suitable value of r. For
:
> deriv(as.freealg("aaabAcx"),"ac")
free algebra element algebraically equal to
- 1*aaabA(da)A(dc)x + 1*aa(da)bA(dc)x + 1*a(da)abA(dc)x + 1*(da)aabA(dc)x
The infinitesimal indeterminates (“da” etc) are
represented by SHRT_MAX+r, where r is the integer for
the symbol, and SHRT_MAX is the maximum short integer. This
includes negative r. So the maximum number for any symbol is
SHRT_MAX. Inverse elements such as A, being represented
by negative integers, have differentials that are SHRT_MAX-r.
Function deriv() calls helper function lowlevel_diffn()
which is documented at Ops.freealg.Rd.
A vignette illustrating this concept and furnishing numerical
verification of the code in the context of matrix algebra is given at
inst/freealg_matrix.Rmd.
Robin K. S. Hankin
deriv(as.freealg("4*aaaabaacAc"),1) x <- rfalg() deriv(x, 1:3) y <- rfalg(7, 7, 17, TRUE) deriv(y, 1:5) - deriv(y, sample(1:5)) # should be zeroderiv(as.freealg("4*aaaabaacAc"),1) x <- rfalg() deriv(x, 1:3) y <- rfalg(7, 7, 17, TRUE) deriv(y, 1:5) - deriv(y, sample(1:5)) # should be zero
The dot object is defined so that .[x,y] returns the commutator
of x and y, that is, xy-yx or the Lie bracket
. It would have been nice to use [x,y] (that is,
without the dot) but although this is syntactically consistent, it
cannot be done in R.
The “meat” of the dot functionality is:
setClass("dot", slots = c(ignore='numeric'))
`.` <- new("dot")
setMethod("[",signature(x="dot",i="ANY",j="ANY"),function(x,i,j,drop){i*j-j*i})
The package code includes other bits and pieces such as informative
error messages for idiom such as .[]. The package defines a
matrix method for the dot object. This is because “*”
returns (incorrectly, in my view) the elementwise product, not the
matrix product.
The Jacobi identity, satisfied by any associative algebra, is
and the left hand side is returned by jacobi(), which should be
zero (for some definition of “zero”).
Function ad() returns the adjoint operator. The adjoint
vignette provides details and examples of the adjoint operator.
The dot object is generated by running script inst/dot.Rmd, which
includes some further discussion and technical documentation, and
creates file dot.rda which resides in the data/ directory.
Always returns an object of the same class as xy.
ignore:Object of class "numeric", just a
formal placeholder
signature(x = "dot", i = "ANY", j = "ANY"): ...
signature(x = "dot", i = "ANY", j = "missing"): ...
signature(x = "dot", i = "function", j = "function"): ...
signature(x = "dot", i = "matrix", j = "matrix"): ...
signature(x = "dot", i = "missing", j = "ANY"): ...
signature(x = "dot", i = "missing", j = "missing"): ...
Robin K. S. Hankin
.[as.freealg("x"), as.freealg("y")] .[as.freealg("x"), as.freealg("y+2z")] .[as.freealg("x+y+2xYx"), as.freealg("x+y+2xYx")] x <- rfalg() y <- rfalg() z <- rfalg() jacobi(x,y,z) # Jacobi identity .[x,.[y,z]] + .[y,.[z,x]] + .[z,.[x,y]] # Jacobi, expanded f <- ad(x) f(y) rM <- function(...){matrix(sample(1:9, 9), 3, 3)} # a random matrix M <- rM() N <- rM() O <- rM() .[M, N] jacobi(M, N, O) plot(.[sin,tan](seq(from=0, to=1, len=100))).[as.freealg("x"), as.freealg("y")] .[as.freealg("x"), as.freealg("y+2z")] .[as.freealg("x+y+2xYx"), as.freealg("x+y+2xYx")] x <- rfalg() y <- rfalg() z <- rfalg() jacobi(x,y,z) # Jacobi identity .[x,.[y,z]] + .[y,.[z,x]] + .[z,.[x,y]] # Jacobi, expanded f <- ad(x) f(y) rM <- function(...){matrix(sample(1:9, 9), 3, 3)} # a random matrix M <- rM() N <- rM() O <- rM() .[M, N] jacobi(M, N, O) plot(.[sin,tan](seq(from=0, to=1, len=100)))
Coerce constant free algebra objects to numeric
drop(x)drop(x)
x |
Free algebra object |
If its argument is a constant freealg object, coerce to
numeric. Modelled on base::drop().
A few functions in the package take drop as an argument
which, if TRUE, means that the function returns a
dropped value.
Robin K. S. Hankin
drop(linear(1:5)) drop(4+linear(1:5)*0)drop(linear(1:5)) drop(4+linear(1:5)*0)
Create, test for, and coerce to, freealg objects
freealg(words, coeffs) is_ok_free(words,coeffs) is.freealg(x) as.freealg(x,...) char_to_freealg(ch) natural_char_to_freealg(string) string_to_freealg(string) vector_to_free(v,coeffs)freealg(words, coeffs) is_ok_free(words,coeffs) is.freealg(x) as.freealg(x,...) char_to_freealg(ch) natural_char_to_freealg(string) string_to_freealg(string) vector_to_free(v,coeffs)
words |
Terms of the algebra object, eg |
coeffs |
Numeric vector corresponding to the coefficients of each
element of the |
string |
Character string |
ch |
Character vector |
v |
Vector of integers |
x |
Object possibly of class |
... |
Further arguments, passed to the methods |
Function freealg() is the formal creation mechanism for
freealg objects. However, it is not very user-friendly; it is
better to use as.freealg() in day-to-day use (although it does
use heuristics for the coefficients if not supplied).
Low-level helper function is_ok_freealg() checks for consistency
of its arguments.
A freealg object is a two-element list. The first element is a
list of integer vectors representing the indices and the second is a
numeric vector of coefficients. Thus, for example:
> as.freealg("a+4bd+3abbbbc")
free algebra element algebraically equal to
+ 1*a + 3*abbbbc + 4*bd
> dput(as.freealg("a+4bd+3abbbbc"))
structure(list(indices = list(1L, c(1L, 2L, 2L, 2L, 2L, 3L),
c(2L, 4L)), coeffs = c(1, 3, 4)), class = "freealg")
Observe that the order of the terms is not preserved and indeed is undefined (implementation-specific). Zero entries are stripped out.
Character strings may be coerced to freealg objects;
as.freealg() calls natural_char_to_freealg(), which is
user-friendly. Functions char_to_freealg() and
string_to_freealg() are low-level helper functions: function
string_to_freealg() takes a length-one character vector such as
"xy" or "-5xxy" and returns the corresponding one-term
free algebra object. Function char_to_freealg() takes longer
character vectors, and returns the sum [sic] of
string_to_freealg() applied to each element.
These functions assume that upper-case letters are the multiplicative
inverses of the lower-case equivalents; so for example
as.freealg("aA") and as.freealg(aBcCbA) evaluate to one.
This can be confusing with the default print method.
Internally, the package uses signed integers and as such can have
.Machine$integer.max different symbols; on my machine this is
2147483647. Of course the print method cannot deal with this as it
only has 26 symbols for letters a-z (and A-Z for the inverses), but
the objects themselves do not care about the print method. Note also
that the experimental calculus facility (as per deriv())
reserves numbers in the range SHRT_MAX for
infinitesimals, where r is the integer for a symbol. This
system might change in the future.
Robin K. S. Hankin
freealg(list(1:2, 2:1, numeric(0), 1:6), 1:4) freealg(list(1:2, 2:1, numeric(0), 1:6)) # heuristics for coeffs: assume 1 freealg(sapply(1:5, seq_len), 1:5) freealg(replicate(5, sample(-5:5,rgeom(1,1/5),replace=TRUE)), 1:5) as.freealg("1+xaX")^5freealg(list(1:2, 2:1, numeric(0), 1:6), 1:4) freealg(list(1:2, 2:1, numeric(0), 1:6)) # heuristics for coeffs: assume 1 freealg(sapply(1:5, seq_len), 1:5) freealg(replicate(5, sample(-5:5,rgeom(1,1/5),replace=TRUE)), 1:5) as.freealg("1+xaX")^5
The formal S4 class for freealg objects
Formal class freealg is used for functions such as drop()
which need a S4 object.
Robin K. S. Hankin
freealg object
The free algebra is a graded algebra: that
is, for each integer there is a homogeneous
subspace with
and
The elements of are
called homogeneous and those of are
called homogeneous of degree (or grade) .
The grade of a term is the number of symbols in it. Thus the
grade of xxx and 4xxy is 3; the grade of a constant is
zero. Because the terms are stored in an implementation-specific way,
the grade of a multi-term object is a disord object.
The grade of the zero freealg object,
grade(as.freealg(0)), is defined to be ,
as per Knuth [TAOCP, volume 2, p436]. This ensures that
max(grades(abelianize(x))) <= max(grades(x)) is always satisfied.
However, a case for NULL could be made.
grades(x) grade(x, n, drop=FALSE) grade(x, n) <- value deg(x)grades(x) grade(x, n, drop=FALSE) grade(x, n) <- value deg(x)
x |
Freealg object |
n |
Integer vector |
value |
Replacement value, a numeric vector |
drop |
Boolean, indicating whether or not to return a
|
grades(x) returns the grade (number of symbols) in each term
of a freealg object x.
deg(x) returns the maximum of the grades of each symbol of
x; max(grades(x)).
grade(x,n) returns the freealg object comprising terms with
grade n (which may be a vector). Note that this function is
considerably less efficient than clifford::grade().
The drop argument to grade() only makes a difference if
either the result is zero, or that n=0 (that is, extracting the
constant). It defaults to FALSE on the grounds that
constant() returns a dropped value.
grade(x,n) <- value sets the coefficients of terms with grade
n. For value, a length-one numeric vector is accepted
(notably zero, which kills terms of grade n) and also a
freealg object comprising terms of grade n.
Returns a disord object
The clifford package includes a similar concept, also called grade.
Robin K. S. Hankin
H. Munthe-Kaas and B. Owren 1999. “Computations in a free Lie algebra”, Phil. Trans. R. Soc. Lond. A, 357:957–981 (theorem 3.8)
X <- as.freealg("1 -x + 5*y + 6*x*y -8*x*x*x*x*y*x") X grades(X) a <- rfalg(30) a grades(a) grade(a, 2) grade(a, 2) <- 0 # kill all grade-2 terms a grade(a, 1) <- grade(a, 1) * 888 aX <- as.freealg("1 -x + 5*y + 6*x*y -8*x*x*x*x*y*x") X grades(X) a <- rfalg(30) a grades(a) grade(a, 2) grade(a, 2) <- 0 # kill all grade-2 terms a grade(a, 1) <- grade(a, 1) * 888 a
Horner's method for multivariate polynomials
horner(P, v)horner(P, v)
P |
Free algebra polynomial |
v |
Numeric vector of coefficients |
This function is (almost) the same as mvp::horner().
Given a polynomial
it is possible to express in the algebraically equivalent
form
which is more efficient for evaluation, as it requires only
multiplications and additions, and this is optimal. Function
horner() coerces its first argument to class freealg.
Robin K. S. Hankin
horner("x", 1:4) # note constant term is 1. horner("x+y", 1:3) # note presence of xy and yx terms horner("1+x+xyX", 1:3)horner("x", 1:4) # note constant term is 1. horner("x+y", 1:3) # note presence of xy and yx terms horner("1+x+xyX", 1:3)
Multiplicative inverses of symbols in the free algebra
all_pos(x) keep_pos(x)all_pos(x) keep_pos(x)
x |
Freealg object |
Function all_pos() tests for its argument having only positive
powers (that is, no inverse symbols present); function
keep_pos() discards any term with a negative power.
At various points in the package, it is assumed that upper-case
letters are the multiplicative inverses of the lower-case equivalents;
so for example as.freealg("aA") and as.freealg("aBcCbA")
evaluate to one. This can be confusing with the default print method.
Even though individual symbols have multiplicative inverses, a general
element of the free algebra will not have a multiplicative inverse.
For example, 1+x does not have an inverse. The free algebra is
not a division algebra, in general.
Robin K. S. Hankin
all_pos(rfalg(include.negative = TRUE)) all_pos(rfalg(include.negative = FALSE)) as.freealg("1+xaX")^5all_pos(rfalg(include.negative = TRUE)) all_pos(rfalg(include.negative = FALSE)) as.freealg("1+xaX")^5
Variables a, b,..., z and their inverses
A-Z are given their freealg semantic meaning.
Sometimes it is convenient in an R session to have all 26 letters a-z
and all 26 uppercase letters A-Z adopt their free algebra
interpretations. To access this, load the lettersymbols dataset,
which is provided with the package in the inst directory:
load(system.file("lettersymbols.rda",package="freealg"))
Executing this allows you to do cool things such as the following:
> (1+a-b^2)^4 free algebra element algebraically equal to + 1 + 4a + 6aa + 4aaa + aaaa - aaabb - 4aabb - aabba + aabbbb - 6abb - 4abba - abbaa + abbabb + 4abbbb + abbbba - abbbbbb - 4bb - 6bba - 4bbaa - bbaaa + bbaabb + 4bbabb + bbabba - bbabbbb + 6bbbb + 4bbbba + bbbbaa - bbbbabb - 4bbbbbb - bbbbbba + bbbbbbbb >
Lowercase letters c, q, t, and uppercase letters
C, D, F, I, T might pose
difficulties.
These objects can also be generated by running script
inst/symb.Rmd, which includes some further discussion and
technical documentation and creates file lettersymbols.rda which
formerly resided in the data/ directory.
Robin K. S. Hankin
Create simple free algebra objects including linear expressions. For example:
> linear(1:3) free algebra element algebraically equal to + 1*a + 2*b + 3*c > linear(1:3, power=5) free algebra element algebraically equal to + 1*aaaaa + 2*bbbbb + 3*ccccc >
linear(x, power=1)linear(x, power=1)
x |
Numeric vector of terms |
power |
Integer vector of powers |
It is instructive to compare the functionality documented here with
their mvp equivalents. Many of the functions documented at
mvp::special.Rd do not make sense in the context of the free
algebra. Function mvp::product(), for example, imposes an
order on the expansion.
Function constant() is documented at constant.Rd, but is
listed below for convenience.
Robin K. S. Hankin
linear(1:3) linear(1:3, power=5) linear(1:3, power=3:1)linear(1:3) linear(1:3, power=5) linear(1:3, power=3:1)
Number of terms in a freealg object; number of coefficients
nterms(x)nterms(x)
x |
Freealg object |
Returns a non-negative integer
Robin K. S. Hankin
(a <- freealg(list(1:3,4:7,1:10),1:3)) nterms(a) nterms(a+1) nterms(a*0)(a <- freealg(list(1:3,4:7,1:10),1:3)) nterms(a) nterms(a+1) nterms(a*0)
Arithmetic operators for manipulation of freealg objects such as addition, multiplication, powers, etc
## S3 method for class 'freealg' Ops(e1, e2) free_negative(S) free_power_scalar(S, n) free_power_free(e1, e2) free_eq_free(e1, e2) free_plus_numeric(S, x) free_plus_free(e1, e2) lowlevel_simplify(words, coeffs) lowlevel_free_prod(words1, coeffs1, words2, coeffs2) lowlevel_free_sum(words1, coeffs1, words2, coeffs2) lowlevel_free_power(words, coeffs, n) lowlevel_diffn(words, coeffs, r) lowlevel_subs(words1, coeffs1, words2, coeffs2, r) inv(S)## S3 method for class 'freealg' Ops(e1, e2) free_negative(S) free_power_scalar(S, n) free_power_free(e1, e2) free_eq_free(e1, e2) free_plus_numeric(S, x) free_plus_free(e1, e2) lowlevel_simplify(words, coeffs) lowlevel_free_prod(words1, coeffs1, words2, coeffs2) lowlevel_free_sum(words1, coeffs1, words2, coeffs2) lowlevel_free_power(words, coeffs, n) lowlevel_diffn(words, coeffs, r) lowlevel_subs(words1, coeffs1, words2, coeffs2, r) inv(S)
S, e1, e2
|
Objects of class |
n |
Integer, possibly non-positive |
r |
Integer vector indicating variables to differentiate with respect to |
x |
Scalar value |
words, words1, words2
|
A list of words, that is, a list of integer vectors representing the variables in each term |
coeffs, coeffs1, coeffs2
|
Numeric vector representing the coefficients of each word |
The function Ops.freealg() passes binary arithmetic operators
(“+”, “-”, “*”,
“^”, and “==”) to the appropriate
specialist function.
Integer powers are implemented. The caret [e.g., a^n with
integer n] denotes arithmetic exponentiation, as in
x^3==x*x*x. As an experimental feature, this is (sort of)
vectorised: if v is a vector of integers, then a^v
returns the sum of a raised to the power of each element of
v. For example, a^c(n1,n2,n3) is a^n1 + a^n2 +
a^n3. Internally, n is tabulated in the interests of
efficiency, so a^c(0,2,5,5,5,) = 1 + a^2 + 3a^5 is evaluated
with only a single fifth power. Similar functionality is implemented
in the mvp package. Beware of bracketing issues:
a^1:3, for example, is not defined (use a^(1:3)).
Negative powers, as in a^n with are implemented: if
a has an inverse, then a^n == inv(a)^(-n); so
a^(n+m)=(a^n)*(a^m) for n,m any integers, positive or
negative.
If x and a are freealg objects, then x^a
implements group-theoretic conjugation. If a has an inverse,
then x^a == inv(a)*x*a. The notation is motivated by the
identities x^(ab)=(x^a)^b and (x*y)^a=(x^a)*(y^a).
The only comparison operators are equality and inequality; x==y
is defined as is.zero(x-y).
Functions lowlevel_foo() are low-level functions that interface
directly with the C routines in the src/ directory and
are not intended for the end-user.
Function inv() is defined only for freealg objects with a
single term. If x has a single term we have
inv(x)*x=x*inv(x)=1. There is no corresponding division in the
package because a/b may be either a*inv(b) or
inv(b)*a.
Robin K. S. Hankin
rfalg() as.freealg("1+x+xy+yx") # variables are non-commutative as.freealg("x") * as.freealg("X") # upper-case letters are lower-case inverses constant(as.freealg("x+y+X+Y")^6) # OEIS sequence A035610 nterms (as.freealg("x+y+X+Y")^6) # OEIS sequence A003462 inv(as.freealg("2aaabAAAAx")) as.freealg("a")^(1:7) x <- rfalg() y <- rfalg() a <- as.freealg("a") b <- as.freealg("b") (x*y)^a == x^a * y^a x^(a*b) == (x^a)^brfalg() as.freealg("1+x+xy+yx") # variables are non-commutative as.freealg("x") * as.freealg("X") # upper-case letters are lower-case inverses constant(as.freealg("x+y+X+Y")^6) # OEIS sequence A035610 nterms (as.freealg("x+y+X+Y")^6) # OEIS sequence A003462 inv(as.freealg("2aaabAAAAx")) as.freealg("a")^(1:7) x <- rfalg() y <- rfalg() a <- as.freealg("a") b <- as.freealg("b") (x*y)^a == x^a * y^a x^(a*b) == (x^a)^b
Given a list of variables, construct every term comprising only those
variables; function pepper() returns a free algebra object
equal to the sum of these terms.
The function is named for a query from an exam question set by Sarah
Marshall in which she asked how many ways there are to arrange the
letters of word “pepper”, the answer being .
Function multiset() in the partitions package gives
related functionality; for the record, one way to reproduce
pepper("pepper") would be
apply(matrix(c("p","e","r")[multiset(c(1,1,1,2,2,3))],nrow=6),2,paste,collapse="")
pepper(v)pepper(v)
v |
Variables to combine. If a character string, coerce to variable numbers |
Robin K. S. Hankin
pepper(c(1, 1, 1, 1, 1, 1, 2)) # 6 a's and 1 b pepper(c(1, 2, 2, 2, 3)) # 1 a, 3 b's and 1 c pepper("pepper")pepper(c(1, 1, 1, 1, 1, 1, 2)) # 6 a's and 1 b pepper(c(1, 2, 2, 2, 3)) # 1 a, 3 b's and 1 c pepper("pepper")
Print methods for free algebra objects. The indeterminates are represented using lowercase letters a-z (currently hard coded).
## S3 method for class 'freealg' print(x,...)## S3 method for class 'freealg' print(x,...)
x |
Object of class |
... |
Further arguments, currently ignored |
The print method does not change the internal representation of a
freealg object, which is a two-element list, the first of which
is a list of integer vectors representing words, and the second is a
numeric vector of coefficients.
The print method uses lowercase letters a-z to represent the indeterminates; this is currently hard coded:
> (x <- as.freealg("6abbbc + 7cax"))
free algebra element algebraically equal to
+ 6*abbbc + 7*cax
> unclass(x)
$indices
$indices[[1]]
[1] 1 2 2 2 3
$indices[[2]]
[1] 3 1 24
$coeffs
[1] 6 7
The print method has special dispensation for length-zero freealg objects but these are not handled entirely consistently.
The print method is sensitive to the value of
getOption("usecaret"), defaulting to “FALSE”. The default
is to use uppercase letters to represent multiplicative inverses. Thus,
the inverse of a appears as either “a^-1” if
usecaret is TRUE, and “A” if FALSE.
Carets become cumbersome for powers above the first. For example, the
default notation for is abAA but becomes
aba^-1a^-1 if usecaret is TRUE.
The symbols for the indeterminates are currently hardcoded as
c(letters, LETTERS). The intent is to be able to signify 52
distinct indeterminates, a-z, A-Z. This works fine if option
usecaret is TRUE. But if option usecaret is
FALSE, this can be confusing: for example, indeterminate number 1
appears as a, and its inverse would appear as “A”.
But indeterminate number 27 also appears as “A”. They
look the same, but no warning is given: caveat emptor!
The method is also sensitive to getOption("mulsym"), defaulting
to NULL. This is the multiplication symbol used between the
coefficient and the indeterminate string. Sometimes an asterisk,
* or a space, might be useful. If mulsym takes its
default of NULL [or a length zero string], the print method
suppresses coefficients of .
Integers exceeding SHRT_MAX are reserved for infinitesimals,
which are printed as “da”; see the note at deriv.Rd
for details.
Robin K. S. Hankin
rfalg() x <- rfalg(inc=TRUE) x # default options("usecaret" = TRUE) # use caret x options("usecaret" = FALSE) # back to the default x x <- freealg(list(5,1:4,3,8,7), c(1,1,1,3,22)) x options(mulsym = "*") x options(mulsym = NULL) # restore defaultrfalg() x <- rfalg(inc=TRUE) x # default options("usecaret" = TRUE) # use caret x options("usecaret" = FALSE) # back to the default x x <- freealg(list(5,1:4,3,8,7), c(1,1,1,3,22)) x options(mulsym = "*") x options(mulsym = NULL) # restore default
Generate random elements of the free algebra, intended as quick
“get you going” examples of freealg objects
rfalg(n=7, distinct=3, maxsize=4, include.negative=FALSE) rfalgg(n=30, distinct=8, maxsize=7, include.negative=FALSE) rfalggg(n=100, distinct=26, maxsize=30, include.negative=FALSE)rfalg(n=7, distinct=3, maxsize=4, include.negative=FALSE) rfalgg(n=30, distinct=8, maxsize=7, include.negative=FALSE) rfalggg(n=100, distinct=26, maxsize=30, include.negative=FALSE)
n |
Number of terms to generate |
distinct |
Number of distinct symbols to use |
maxsize |
Maximum number of symbols in any word |
include.negative |
Boolean, with default |
Terms are automatically simplified; for example,
aaBaAbaC will be simplified to aaaC.
Functions rfalgg() and rfalggg() return successively
more complicated freealg objects.
Robin K. S. Hankin
rfalg() rfalg(include.negative = TRUE)^2 constant(rfalg())rfalg() rfalg(include.negative = TRUE)^2 constant(rfalg())
Substitute symbols in a freealg object for numbers or other
freealg objects
subs(...) subsu(S1, S2, r)subs(...) subsu(S1, S2, r)
S1, S2
|
Objects of class |
r |
Integer specifying symbol to substitute ( |
... |
First element is a |
Function subs() substitutes variables for freealg objects
(coerced if necessary) using natural R idiom. Observe that this type
of substitution is sensitive to order:
> subs("ax",a="1+x",x="1+a")
free algebra element algebraically equal to
+ 2 + 3*a + 1*aa
> subs("ax",x="1+a",a="1+x")
free algebra element algebraically equal to
+ 2 + 3*x + 1*xx
Functions subsu() is a lower-level formal function, not really
intended for the end-user. Function subsu() takes S1 and
substitutes occurrences of symbol r with S2.
No equivalent to mvp::subvec() is currently implemented.
Returns a freealg object.
Function subs() is one place in the package where the use of
letters is effectively hard-wired in. Idiom such as
subs("abccc",b="1+3x")
is very nice, but identifies “b” with 2. Note that argument
r of subsu() is canonically an integer but a single
character is interpreted as a letter. See also the note
at freealg.Rd.
Robin K. S. Hankin
subs("abccc", b="1+3x") subs("aaaa", a="1+x") # binomial subs("abA", b=31) subs("1+a", a="A") # can substitute for an inverse subs("A", a="1+x") # inverses are not substituted for a <- rfalg() subs(a, a=a) ## Sequential substitution works: subs("abccc", b="1+3x", x="1+d+2e") subs(rfalg(), a=rfalg())subs("abccc", b="1+3x") subs("aaaa", a="1+x") # binomial subs("abA", b=31) subs("1+a", a="A") # can substitute for an inverse subs("A", a="1+x") # inverses are not substituted for a <- rfalg() subs(a, a=a) ## Sequential substitution works: subs("abccc", b="1+3x", x="1+d+2e") subs(rfalg(), a=rfalg())
Test for a freealg object's being zero
is.zero(x)is.zero(x)
x |
Object of class |
Function is.zero() returns TRUE if x is indeed
the zero free algebra object. It is defined as
length(coeffs(x)) == 0 for reasons of efficiency, but
conceptually it returns x == constant(0).
(Use constant(0) to create the zero object).
Robin K. S. Hankin
stopifnot(is.zero(constant(0)))stopifnot(is.zero(constant(0)))