NewASDoc.tioga
Dennis Arnon, November 23, 1987 2:38:36 pm PST
CEDAR 7.0 — FOR INTERNAL XEROX USE ONLY
New AlgebraStructures
Dennis Arnon
© Copyright 1987 Xerox Corporation. All rights reserved.
Abstract: AlgebraStructures is an object-oriented package for building complex algebraic structures and computing with their elements. For example, one can quickly read in and do simple arithmetic on matrices of polynomials with complex number coefficients, or matrices of such matrices, ad infinitum.
Created by: Dennis Arnon
Maintained by: Dennis Arnon <Arnon.pa>
Keywords: Computer Algebra, Symbolic Mathematical Computation, Polynomials, Matrices, Object-Oriented Programming
XEROX Xerox Corporation
Palo Alto Research Center
3333 Coyote Hill Road
Palo Alto, California 94304
For Internal Xerox Use Only
1. General notes on Objects and Databases
Perhaps there should be a basic CedarChest package of "ObjectOrientedDB", i.e. type & value Objects, plus online and offline Objects, storage/retrieval of offline Objects in LoganBerry DB's, plus management of the online Objects.
There can be one or more LoganBerry databases around at any one time. AlgebraStructures provides management of "AlgebraStructures/LoganBerry" databases, i.e. procs for offlining/onlining Objects to/from such db's.
AlgebraStructures provides a online datastructure (cache) for keeping a certain collection of Objects online. Basically an offline Object has a class of OffLineObjectClass, whose methods and data are primaryKey, i.e. key for search of a LoganBerry DB, and openDB: LoganBerry.OpenDB, to identify which DB. If you know an Object is online, then you can reference its .class and .data fields directly, otherwise use Objects.Class[object] and Objects.Data[object], which first check whether the object is offline, and if so, online it. Also there are various flavors of MakeObject, e.g. offline it immediately, keep it online with a certain priority, etc.
Also, there should be a proc that is either MakeOfflineObject, or SaveKeysForOfflining, that takes a list of attribute (type, value) pairs that will be saved with the object when it is offlined.
2. Checking Objects for equality
Every Structure should have an Equal predicate. This defines the meaning of "having the same Object". I.e. we don't mean equality of pointers, we mean semantic equality.
2. General notes on Flavor procs
How Flavor procs work: basically, narrowing the given Object and seeing if it is a StructureData or an ElementData or a MethodDictionary.
3. General notes on Domain creation
Should have procs like MakeGroupClass that take a list of methods and do all the rest.
4. Inheritance
We only support n-ary inheritance for some fixed n (currently n = 1). Additional superclasses are methods.
Superclassing intended only for "axiomatic inheritance", e.g. PolynomialsOverField as a subclass of PolynomialsOverRing. "Subsetting", i.e. that the integers are a subset of the rationals, should be accomplished by WidenThis procs. Here we only support "single widening". Thus we must define a linear ordering of domains, e.g. integers -> rationals -> algebraics -> reals -> complexes -> 1x1 vectors -> 1x1 matrices -> polynomials in x with 1x1 matrix coefficients. This should be the same linear ordering used by the "NarrowestCommonSuperStructure" proc.
A general description of the more sophisticated use of axioms, rewriting, and reasoning that we would like to see in AlgebraStructures is to be able to support multiple inheritance and better NarrowestCommonSuperStructure procs. One sense in which we mean "better" is "more dynamic", e.g. that we don't have to have carved in Cedar code that polynomials over a field have division and remainder procs, but that the system could automatically generate the correct subclass structure, i.e. the correct inheritance.
5. NarrowestCommonSuperStructure procs
1a. Seems like there has to be one such proc global to the whole system, unless somehow each particular domain can handle all types that are "less" than themselves in the type ordering. The type ordering itself should be in a file or other "user profile", so we can change it and immediately alter the system's conversion behavior.
Not every type must participate in the type ordering, e.g. QE types may not. Such types do not narrow at all, and only widen to General Expressions.
1b. A general prescription for writing NarrowestCommonSuperStructure procs?: dynamic programming approach: follow a chain of calls to WidenThis procs for one arg, each time trying to WidenOther the other arg into the current structure, then do the same for the other arg. Pick the "least cost" upper bounding Structure found in this way.
1c. Sample orderings:
BigInt < BigRat < Algebraic < Real < Complex <
Vector < Matrix < Polynomial < Formula < Set < List < Sequence
2. If constructor B appears after A, then this should mean that B's WidenOther proc can handle Objects of type A (e.g. Polynomial should be able to widen any Matrix). In other words, WidenOther procs should be able to handle all types that come before them in the type ordering.
3. It is not necessarily the case that A's WidenThis proc should create an object of type B, if B is immediately after A in the ordering. Thus BigRats widen proc conceivably could widen to matrix or polyomial, rather than Real.
4. The general alg is: assume that we have two objects O1, O2 of the same type T, and constructors A(T), B(T) [For e.g. vector or matrix constructors, O2 could be a list of Objects.] If A comes before B in the ordering of constructors, we apply A to T; if can't be done, fail. Else we lift all Objects to be of type A(T), and now we have A(T), B(A(T)). If we can't apply B to A(T) then fail, but shouldn't happen because B's WidenOther proc should be able to handle everything that comes before it in the ordering of types. Otherwise we widen A(T) to B(A(T)), and finish.
Suppose instead we had started with C(A(T)) and B(T). Then we would have C(A(T)) and B(A(T)) after the first step. Then we would continue by comparing B and C, and supposing that B comes before C, we would next get C(B(A(T))) and B(A(T)), and finish by widening B(A(T)) to C(B(A(T))).
5. Instances of the same constructor with different parameters may or may not cause failure. For example, if Matrices(*,2,2) and Matrices(*,3,3) are the next most outer constructors, we probably want to fail, but if Polynomials[*,[x]] and Polynomials[*,[y]] are the next constructors, we probably want to coalesce these to Polynomials[*,[x, y]].
6. Dynamically adding methods to classes
Want a clean way of dynamically adding methods to existing classes, e.g. we want to be able to add factorization and root isolation methods to polynomials class, or basis and projection methods to PolynomialSequences class, by just running these later modules.
Perhaps should be done as follows: simple way: if no new subclass needed, have the original class be public and just add the method to it. complex way: define a new subclass as needed for the new method, e.g. univariate integral polynomials for factorization, and replace the MakeStructure proc so that it detects instantiation of a Structure in that subclass, and gives it the newly defined (sub)class.
1. General Ramblings
1.2. Semantics
We have a single fixed class record for all instances of structures in that class. That is, all instances of structures in the class will contain a pointer to exactly the same record in memory.
A class record contains only procedures. Property lists provide a primitive subclassing mechanism. That is, for each given type of class record (group, ring field, etc.), we can instantiate variations of it with different property lists. The procedure-only principle extends to property lists - they contain only procedures.
We seek to enforce the paradigm that data (e.g. matrix size, variable list, minimal polynomial) pertains to particular instances of structures, and that it goes in the instance record of each particular structure.
Certain familiar structures, e.g. integers, reals, bigrats, are automatically created by the package.
For some differences between algebraic structures it is clear that we need different built in kinds (classes) of structures (e.g. group, ring). Having established our builtin kinds of structures, it is clear that there can be small differences among structures of a given kind; these distinctions we make via the property list (e.g. ordered rings). Properties possessed by all structures of a given kind (e.g. identity, characteristic for rings) are in the class record for that kind, provided that (1) their values can be obtained by invoking procedures, (2) it is reasonable that the parameters of such procedures be REF ANY, or a particular structure kind, which is all we have available in the AlgebraClasses interface. Properties not meeting these requirements, and clear interface data, have to go in later interfaces.
For some "properties" it is less clear where they should go; generally we put them on property list (e.g. Euclidean domain). The value of a property may be a record of operations that are available because a structure has a given property (e.g. comparison ops made possible by order property).
Our view is that an algebraic structure consists of two things - a class record of operations (some are defined for all rings, and others, on the propList, are defined only for some subclass of rings), and instance data.
The ring class record contains procedures for the class, where a "class" of rings is all those rings builts up using a particular constructor. We can take the definition of what proc definitions belong in the constructor interface as: those which are the same for all rings in the class.
Something that allows us to get polymorphism out of our structuring interfaces, e.g. polynomials, matrices. Each particular flavor of polynomial or matrix is defined to be a just a generic polynomial or matrix, e.g.
RatPolynomial: TYPE = Polynomials.Polynomial;
One way that this pays benefits is that the ring instantiation procedures can be in the constructor interface, because when the class procs do their NARROWs, they get generic polynomials.
The interface for a new structured ring can get a handle to its ground ring in one of two ways: either the ground ring has already been instantiated in some other interface, or we instantiate it in this interface. In either the case, the direct procs just call appropriate constructor procs, passing them the ground ring.
The place where type checking really happens is when we get down to operations on the ground ring, i.e. the class procs for the ground ring will do NARROWs which will fail if the wrong ground ring is present at the bottom.
The interface for a structured ring contains two things.
(1) the instantiation of the ring.
(2) direct procedures for operating on elements of the ring.
The direct procs have inputs and outputs of the particular structured ring type. They utilize the structuring operations to do their computation. They don't have to NARROW their inputs, but they do have to NARROW the outputs they get back from structuring operations.
To instantiate the ring, you define class procs which narrow their arguments and call the direct procs. Obviously there is no need to "widen" the outputs that come back from the direct procs. You might say that the NARROW done by the direct proc is wasted effort, but this is the price one pays for the convenience of having the direct procs, which anyone who is a direct client of this ring will use.
The standard naming convention is that the direct procs have names which mimic the fields of a ring class, e.g. "Multiply", and the class procs simply put the word "Class" before this.
If you get an op for a ring via its class record (as is done e.g. by structuring operations), you have to NARROW the result, since by definition, AlgebraClasses.UnaryOp, BinaryOp, etc. return a REF.
A finished, structured ring knows what its ground ring is, and even though that information is not in its elementType declaration (e.g. we define RatPolynomial: TYPE = Polynomials.Polynomial), it will be used in ring's direct procs, and indeed, the ground ring should be clearly stated somewhere at the beginning of the interface. Thus, in order to build up a structured ring you have in mind, all the "lower order" rings have to exist, i.e. have been instantiated, and you have to know what at least the outermost of the interfaces containing those instantiations is to get your hands on the outermost ground ring you need.
1.3. Fancy operations
We expect that, in general, one will want additional operations on a ring than those provided by its class record or property list. These will be implemented by a separate sequence of interfaces. Thus, if one wanted an integer polynomial factorization algorithm that did complete factorization of the integer content, it would be necessary to have an integer factorization routine. To us it is appropriate that you do not, and do not expect to, find such a procedure in the class record or property list for the integer ring.
There seems little uniformity in how much genericity will be possible in such modules. Thus it seems clear that one can have generic polynomial division and real root isolation modules. Gcd seems clearly to admit genericity for prs algorithms (since pseudodivision does), perhaps for Chinese remainder lifting of variables, for multivariate polynomials over a field (use prs algorithm at univariate base), and not at all for Chinese remainder lifting of integer coefficients. There appear to be two kinds of polynomials we want to factor, rational and algebraic, possibility of genericity unclear.
This point of view has an algebraic interpretation - we are saying that the only kinds of "finer grain" ring operations we are willing to build into the class structure are ordered rings and fields. Operations pertaining to euclidean domains, or unique factorization domains, have to be implemented outside the ring structure. Thus the ring structure makes it easy to get I/O and basic ring operations for algebraic polynomials, giving you a platform from which to separately do the additional work to e.g. get factorization.
1.4. Modus operandi
We try to follow the rule that there is one class record for more than one domain. However the sequence constructor violates this; every time you make a new sequence structure you make a new class record. The problem here is not that we have a class that has only one domain in it, but the "lack of uniqueness" aspect: we unfailingly create the new class record every time, regardless of whether we might already have made this kind of sequences.
This can be dealt with by having unique hashcodes for structures, and a registry of all created structures, and then every structure constructor checks the registry to see if a requested structure is already there. This could be handy if someone tries to recreate the basic structures, or e.g. to prevent algebraic number routines from multiply recreating the same algebraic number field. Hashcodes should probably be ropes.
There is a tension between having e.g. a PolynomialOpsRec that goes on the property list, and simply having procs in the interface; currently we do both (i.e. we're redundant). The general problem is that we have a single kind of StructureClassRec defined in AlgebraClasses, that has to be made to serve all algebraic structures. A better mechanism would be to simply put REF PROC's on the property list, plus build up a list of the available ops. Only the things which absolutely every structure has, e.g. a printNameProc, would be hard fields of the class record. Algebraclasses would export a "dispatcher", which would take in the name of a desired proc and know whether to get it out of a record field or off the proplist.
The general issue is - how to make all knowledge about what procs are available in a structure exported to clients by the run-time structure (ideally even including documentation, perhaps a la pop-up buttons). Then the CaminoReal user interface could be just like any other client, and would contain no hardwired knowledge of the underlying algebra system, except for knowledge of the generic mechanism by which the specifications of a structure are encoded.
We then have a field in class records in which is stored a list of triples: property name, whether in class record or a proc on property list or a property value on the property list, and a documentation rope. Class record then offers procs to tell you whether a property exists at all, or to get its value on the assumption that that value is a proc, or to get its value on the assumption that that value is a bool, or to get its value on the assumption that that value is a rope, etc. Also there is a proc to do a full printout of the triple list - names, nature of values, and documentation ropes. Some other proc returns a list of (standardly modified, e.g. remove "$") names of proc-valued properties; this can then become part of the pop-up menu of ops for that structure.
AlgebraClasses offers a proc that takes five args (a StructureClass variable, a PropName, a Ref that is the prop value, a specification of the nature of the value, and a documentation rope), and does two things: puts the prop on the StructureClass's proplist with the specified value, and adds the (PropName, specification of the nature of the value, documentation rope) triple to the list of triples stored in that StructureClass). The Impl module for a class then has as part of its start code a call to this proc for each op associated with the class.
A basic convention is that the procs implementing structure ops should all have types defined in AlgebraClasses.
Thus we insist that our structures are "run-time self-documenting". The run-time user can find out in a standard way what's available in a structure. The client is expected to look at the interfaces, or perhaps there is a manual that tries to stay up to date (one way it might stay up to date is to regenerate itself on the fly, i.e. whenever you want to display it, it goes off and actually calls the same sort of procs we have been talking about, in all the interfaces, to produce a list of what ops are available).
MethodApplier:
PROC [methodSelector:
ATOM, argList:
LIST
OF Object, structure: Object ←
NIL]
RETURNS[value: Object];
Pass structure = NIL if you just want to try method from firstArg structure first
ok:BOOL;
movingPointer, outArgs: LIST OF Object;
arg: Object;
CheckArgs:
PROC [methodSelector:
ATOM, argList:
LIST
OF Object, structure: Object]
RETURNS [ok:
BOOL, outArgs:
LIST
OF Object ←
NIL] ~ {
desiredArgStructures: LIST OF AC.Object;
outArgs: LIST OF Object ← NIL;
IF NOT AC.CheckMethod[methodSelector, structure] THEN RETURN[FALSE ! "No such method"];
desiredArgStructures ← AC.DesiredArgStructures[methodSelector, structure];
WHILE desiredArgStructures #
NIL
AND argList #
NIL
DO
desiredArgStructure ← desiredArgStructures.first;
desiredArgStructures ← desiredArgStructures.rest;
arg ← argList.first; argList ← argList.rest;
IF
AC.StructureEqual[desiredArgStructure, arg.structure]
THEN
IF outArgs = NIL THEN outArgs ← LIST[arg] ELSE outArgs.rest ← LIST[arg]
ELSE {
recastArg ←
AC.PerformMethod[$Recast, desiredArgStructure,
LIST[arg] ];
-- automatic type conversion occurs here. An alternative is to have all methods like Recast, which every structure has, in AC as concrete procs:
recastArg ← AC.Recast[desiredArgStructure, arg];
IF NOT AC.StructureEqual[desiredArgStructure, recastArg.structure] THEN RETURN[FALSE ! "Type clash in arg j"];
IF outArgs = NIL THEN outArgs ← LIST[recastArg] ELSE outArgs.rest ← LIST[recastArg];
};
ENDLOOP;
IF desiredArgStructures #
NIL
OR argList #
NIL
THEN
RETURN[FALSE ! "Bad Number of Args"]
ELSE RETURN[TRUE, outArgs];
};
Try method from suggested structure first, if any
IF structure #
NIL
THEN {
[ok, outArgs] ← CheckArgs[methodSelector, argList, structure];
IF ok THEN RETURN[AC.PerformMethod[methodSelector, structure, outArgs] ];
};
movingPointer ← argList;
WHILE movingPointer#
NIL
DO
arg ← movingPointer.first; movingPointer ← movingPointer.rest;
[ok, outArgs] ← CheckArgs[methodSelector, argList, arg.structure];
IF ok THEN RETURN[AC.PerformMethod[methodSelector, arg.structure, outArgs] ];
ENDLOOP;
SIGNAL NoApplicableMethodFound;
END;
A basic rule: every method must return exactly one object.
AC.CheckMethod, AC.DesiredArgStructures, AC.PerformMethod, etc. look in the method dictionaries of their structure arguments, and if need be, the method dictionaries of their superclasses.
6/20/87 - Consider a Structure S whose class (i.e. the value of field S.class) is C (C is an Object of flavor Class). There are two possible flavors of superclasses (i.e. flavors for C.class) in this situation: Class or Structure. The first sort is obvious - consists of methods, corresponds to inclusion of categories. The second sort is only appropriate in case S is the only Structure in its class. Then if S is a substructure of a Structure T, we can set C.class to T. The obvious example is Integers are a substructure of Rationals are a substructure of Reals. The effect is that if we are searching for methods and don't find them in C, and we see that C.class is a Structure T, then we will continue our search in T.class. It is assumed that if C.class = T, then T's recast proc can handle elements of S.
At the moment only single inheritance is supported. Can fake by having superClass methods in Class.
General note on inheritance: the Smalltalk paradigm seems to assume that a class has one model: a subclass is a subset of that model consisting of all elements that have some further property. Thus the (unique) model of a subclass is a subset of the (unique) model of the class. The situation we have with algebraic structures is rather multiple models. I.e. we have a category, e.g. the real closed fields. All models in this category may have an add op, but you can't give a single particular add proc that will work for all models.
How do Views, Scratchpad, etc. deal with this issue?
2. AlgebraStructures improvements
2.1. Integer arithmetic, quotient constructor.
Combiner uses CaminoReal.
Separate BigRats for CedarChest like BigCardinals, not AlgebraStructures?
2.2. New Domains
Vector type: Use it or point or sequence for RatIntervals, Variables.
EquationsOver, RelationsOver (similar to FormulasOver). Quantifier-free formulas over?
Add existential, universal quantifiers.
2.3. Extensibility issues
How should users specify new operators, or new domains? Need to specify things like canonical forms, formatting rules for legal expressions.
2.4. Recast (conversion) issues
Automatic conversion where appropriate, or tell user to modify domain if he want that op?
How hard is automatic domain inference for an arbitrary expression (Scott Morrison)?
2.5. Substitution facility
What are the correct specifications of a general substitution facility?
1. Goals
1. Reduce, Macsyma, SAC-2 servers (a la Dictionary server).
1. Ability to transmit and run programs with Macsyma, SAC-2, and REDUCE.
1. Note on Single Set Structures
Currently the only case in which Eval will choose this sort of Structure for something it reads is for variables.
2. Structure Names
Structures have (long) names which should also be recipes for constructing them. These long names are stored with an element of that domain which is placed in a Tioga doc.
Structures have short names, intended to capture standard usage (e.g. Q[x, y]), which are, for example, displayed in a CaminoReal viewer to tell the user the domain of a certain object.
Default structure for all exprs is MeddleExpr's.
2. Structure Elements
There are two ways to get a structure element, i.e. to get an AlgebraStructures internal rep of an object belonging to a particular domain: convert an editor expression to AlgebraStructures internal rep (FromExpr op), or parse a ROPE into an AlgebraStructures internal rep.
3. ToExpr and FromExpr ops
Both should be available in every structure, and should be inverses of each other.
Thus note that, in particular, we assume that the editor offers sufficient (currently hardwired) display functions, and that for the elements of any AlgebraStructures structure, we can give a recipe for displaying it in terms of editor functionality.
3. TestDomain op
What this does is take an editor expression and check that, if evaluated, it will indeed be an element of the specified domain. Does no evaluation/simplification.
3. ImbedInDomain proc
There is a single such proc for the whole AlgebraStructures system.
Takes an editor expression and domain, and tries to evaluate the expression to an element of the specified domain. First does a TestDomain op. If that succeeds, then evaluates/simplifies the given editor expression to an AlgebraStructures internal rep for the value, and, by applying the ToExpr op of the structure, also returns an editor expression for the evaluated/simplified form.
For polynomials, is a highly recursive proc.
Has rules, for example if domain is Z and expr is Det(matrix of ints),
3. Structure Recast procs
Should always do something on general expr rep = meddle internal form. This is the proc that is applied when we assert that something we've created in the editor is an element of some domain. Does evaluation, e.g. if domain is ints, and expr is determinant of matrix of ints, should be able to check that determinant method exists in matrix structure, call matrix structure recast proc to convert Should work recursively, i.e. when applied to a poly, knows to call coeffRing recast proc on coefficient.
Actually, each time you come to a component part, check to see whether it already has a domain. If so, and if that domain is the desired one, done, else, apply the desired domain's recast proc to the FromExpr(MeddleInternalForm) of the object. This should permit editor copying of expressions which already have a domain, into parts of an expression which doesn't.
Meddle Expr's should have a ValidObject BOOL, i.e. if the expr has a domain, and it has been checked to be a valid element of that domain, then TRUE, else FALSE. Set to FALSE whenever an Expr changed.
A different philosophy: you never trust an editor entity.
So, e.g. there should be a polynomial expression type in Meddle, which is a list of terms.
Defn of canRecast: Really applies to two structures: Can any element of the first be recast as an element of the second?
3. The Type Inference problem
A general rule for structure lub'ing. LUB(Variables, Variables) = Variables. LUB(Variables, Any arithmetic structure) cannot in general be done, unless perhaps we have a structure "Polynomials with specified coefficients but unspecified variables).
Point is that LUB Structure for a Variable and an arithmetic, non-Variable Object cannot be done just by LUB'ing their respective Structures. Because to determine this LUB we want to interpret the Variable as being in Z[var].
Thus we will assume that when this situation occurs, we have our hands on the actual variable.
Note: General Expressions are contagious to polynomials, i.e. LUB(anyPolynomialStructure, GeneralExpressions) = GeneralExpressions. Thus there cannot be "polynomials over GeneralExpressions".
However, there can be matrices over GeneralExpressions. This enables to do a matrix mult, with each element of the product matrix a GeneralExpression. Doing this sort of thing points up need for simplifier for general expressions. This appears to be the "strongest" sort of domain currently.
2. Creating Domains
The current Ground Domains likely to be of interest to the general user are:
Bools, Colors, FormulaOperators, Integers, Rationals, Reals, Complexes
Polynomials
For any polynomial, we need to keep track of 'what variables it's a polynomial in'. This is accomplished by associating a variable sequence with the polynomial. This is a sequence of Ropes (the variables). In order for scanning to work, variables should be Cedar identifiers. A variable sequence should be written as comma-separated variables enclosed in parentheses (whitespace ok anywhere except within a variable). For example, "(x,y,z)".
When you have a variable sequence into the ScratchPad, and some coefficient domain, you can apply the polynomial constructor.
Matrices
These are rings of square matrices of specified size, whose entries are belong to a specified domain.
3. Algebra-format Ropes for Objects
The reader may find it a useful exercise, for each of these examples, to create an Item, set its WorkingDomain appropriately, Tioga-select the Algebra-format Rope given below for a sample element of that Domain, bug the OperateWorkingDomain button, and choose the FromLinearRope operation. In each instance, you should get a new Current Object and corresponding Display Expression.
You can always see what CaminoReal thinks is an appropriate Algebra-format Rope for the Primary Selection by bugging the "ToASRope" button.
1. Complex Numbers
Algebra-format Rope: (-38368.0 + 22976.0 i )
At present, CaminoReal insists that anything that is to be considered a complex number must be created with the complex template from the menu, and hence be displayed in the form X. Thus for example, complex zero must be dealt with as X (or X; the presence or absence of decimal points doesn't matter) and complex one as X. Also, complex numbers with negative imaginary part will appear as in this example: X. Given this rigidity, one can perhaps live with the fact that complex numbers are not enclosed in parenthesis, e.g. here's an example of how CaminoReal currently prints a polynomial in x with complex coefficients: X
2. Polynomials
A polynomial is written as a sequence of terms in the variables of that list. Order of terms doesn't matter. Multiplication is implicit (whitespace between coefficients and variables). Exponentiation is indicated by either "^" or "**". Order of occurrence of variables in a term doesn't matter (no duplicate monomials allowed, however). Error if a variable not in the variable sequence occurs, but not all variables in the list need occur in any given polynomial. Case matters in variables. Order of occurrence of variables in a term doesn't matter.
No simplification currently supported in input, e.g. (x + y)^2 is illegal.
For example, suppose Domain is Polynomials in (x, y, z) over the Rationals
.
Algebra-format Rope: x z^33 - 92837498279872983749734 / 33 y**23 + x y z - 1
3. Matrices
Domain is 2 x 2 Matrices over Polynomials in (x) over the Complexes
.
Algebra-format Rope: [ [ x , (1.0 + 1.0 i ) x^12 + (0.0 - 1.0 i ) ] , [ x^3 , x ] ]
4. Algebraic Numbers (see Section 14)
Suppose the domain is extension of Rationals by the unique real root of X between -2 and -1.
Algebra-format Rope: [ x^3 + 647364/19 x^2 - 3 x + 1/8 ]
Display Expression: X
4. Domains and Objects for Algebraic Numbers, Curves and Surfaces
The RealAlgebraicNumbers constructor is applied to a domain of univariate polynomials over the Rationals, e.g. Q[x]. Having set the Working Domain of an Item to this Domain, a particular real algebraic number can be created from two Objects (which must be attached to other Items): an element of the appropriate domain of univariate polynomials (this should be an irreducible polynomial), and an isolating interval for a particular real root of that polynomial. For example, the polynomial might be:
X
and the isolating interval
The latter can be constructed as an element of the domain of Points of length 2 over the Rationals. Primary select the polynomial and secondary select the interval. Then in the Viewer whose Working Domain is Real Algebraic Numbers, bug OperateWorkingDomain, choose the MakeAlgebraicNumber option in the popup menu, and you will see the algebraic number displayed. For the above example, the result would be:
X
The ExtensionField constructor can only be applied in an Item whose Current Object is a Real Algebraic Number (for example the one we just constructed). Just select ExtensionField from the Working Domain menu, and the domain constructed is the extension of the Rationals by that Real Algebraic Number. Mathematically, the elements of this domain are now univariate polynomials in the appropriate variable reduced mod the minimal polynomial. In CaminoReal, we write them as a length one vector whose single element is a polynomial. Thus, continuing with the above example, if we create a Current Expression of
X
(primary) Select it, and bug SetObject, after reduction mod the minimal polynomial of X, we will get:
[The FormulaOperators and Cads ground Domains, and the Formulas, RealAlgebraicNumbers, ExtensionField, SamplePoints, CoveringSets, and Cells structuring operations are used, for algebraic curves and surfaces. Cad2DViewer is used for displaying algebraic curves. Exercising this stuff involves a detour through the Vax currently; consult Arnon if interested.]