Package cox.jmatt.java.MathTools

These are MathTools' core classes.

See:
          Description

Class Summary
Arithmetic This class provides methods for creating and manipulating numbers digit-wise.
CapCom This class, consisting solely of static methods, provides a central logging point and data repository.
MathEngine This is the power-class of the MathTools package.
MathSet This class acts as an immutable container for sets and provides equipment for formatting questions involving them.
MathStat This class gives MathTools its statistical component.
MathXML This class provides XML and MathML Presentation markup utilities to the other MathTools classes.
MComplex This class provides MathTools support for imaginary and complex numbers.
MEquation MEquation's purpose is to provide a fast and easy way to generate simple equations commonly found on algebra tests.
MFraction This class encapsulates the behavior and manipulation of fractions.
MMatrix MMatrix represents a mathematical matrix, a rectangular array of numbers.
MRadical The MRadical class provides an easy way to create and present radicals without requiring double approximation or other theatrics.
Percent The Percent class encapsulates all the machinery necessary to calculate simple percents.
Polynomial This class encapsulates polynomial behavior.
Question This is MathTools' basic unit of data storage and presentation.
 

Enum Summary
MathXML.MathSymbol This enum is used to hold Unicode math symbols and to provide them and their values in an easily accessible way.
MEquation.Equation This enum specifies the standard types of equations contained within the MEquations class.
 

Package cox.jmatt.java.MathTools Description

These are MathTools' core classes. They represent the actual classes exposed to scripting languages. All classes have static methods to create more of themselves and the MathEngine also provides factory methods for obtaining other things. Another source for instances of these classes is the MathTools Applet. MTApplet acts as a receiver for logging and print messages and provides a way for scripts in HTML documents to have access to MathTools.

CapCom

CapCom provides a central access point for logging and data storage. It is not script-accessible and, in fact, consists of static methods along with a private final constructor: it is NEVER meant to be subclassed or instantiated. Rather, all of the other MathTools classes use it for logging and communication. Applications utilizing the MathTools package may (and should!) use CapCom; it has several convenient features provided for such.

CapCom communicates with the outside world via a MathPrinter. It has a method to set one, the Global Printer, and that is what receives all logging, print, and process requests. CapCom is written to provide logging for MathTools but it is also designed so as to allow other classes written using MathTools to take advantage of its services. To this end it provides rudimentary data storage and retrieval equipment.

Data Storage and Retrieval: Pizzas and The Shelf

CapCom provides a way for applications to store and retrieve arbitrary Objects. The Shelf is backed by a Hashtable<String, Object> and CapCom provides methods to store an Object, retrieve it, and remove it. The MathConsole has access to the storage and retrieval methods but NOT the removal method.

The Global Pizza is a java.util.Properties object CapCom holds and makes available if requested. It allows scripts access via the MathConsole, so simple String properties can be accessed easily.

Question

Question is the presentation class of the MathTools package. It contains both static methods useful universally and instance methods for customizing each question. The class itself encapsulates all the elements of a test question: an ID (question number), a Problem, and an Answer. Question also contains the machinery necessary to format both problems and answers in a consistent yet flexible way.

One particularly useful method is validString(). It is a static method that accepts a String as a parameter and returns true if and only if the supplied String is not null or empty. Almost all MathTools classes make use of this method at least once. Question also provides static methods to create more Questions, and many other MathTools classes have methods that return Question objects.

Formatting Things

Question's power-method is fillTemplate(). It provides a very basic templating engine. The method itself takes a specially-formatted template String and a String[] array of replacement tokens. It then replaces each numbered token with the corresponding element from the array. This is useful by itself but is much more powerful in conjunction with other machinery.

Question has six internal formats for presenting its components. Each of these formats is itself a template, so when Question formats its answer it merely sends the data to fillTemplate(). In the (likely) event that the built-in formats are not adequate, each individual Question can have its format pre-set. The format itself is nothing more than a template String with each component assigned a specific token number. (This also applies to the pre-set formats!) So, to change the presentation format of the Question requires nothing more than creating an appropriate template!

MathEngine

This is the power-class of the MathTools package. It provides a core set of tools useful for creating mathematical questions. The first of these are its random number generators. MathEngine's random() function implements a pseudorandom generator. Although it probably is not strong enough for serious cryptographic work it is certainly random enough for creating math tests! MathEngine also provides two methods for re-seeding the generator: one in which the seed value is supplied and one that uses the system clock. Because of this, MathEngine can generate 'deterministically random' numbers: if necessary, exact random sequences can be replicated. This allows for easy testing when MathTools are used and sufficient randomness when they are deployed. MathEngine supplies two integer-generating random functions: random(int, int) and nzRandom(int, int). The former generates a random number from the range given, including the low value but excluding the high one. The nzRandom() method does the same but guarantees that the result will NOT be zero.

Knobs

A Knob is a random number generated from a range. What distinguishes Knobs is that more than one can be generated at a time. MathEngine.setKnobs() takes a String of space-separated integers and generates one random number for each pair of numbers supplied. For instance, setKnobs('0 10 -5 15 12 37 -100 -45') returns a 4-element int[] array with element 0 from [0, 10), element 1 from [-5, 15), element 2 from [12, 37) and element 3 from [-100, 45). Useful by itself but even more impressive when combined with other methods.

Calculation

MathEngine implements a very basic RPN calculator. It is a stack-based 'machine' with the stack and two registers. In use, it parses an RPN-formatted numerical expression, performs the calculations, and returns the answer. So, to enter the problem '2 + 3 * 4' would be '2 3 4 * +'. This method allows fairly complex calculations to be performed dynamically, without requiring hard-coding in the application itself.

The parseRPN() method itself has two modes of operation: integer and floating-point. Integer mode is the default and preferred mode. Calculations are done using integer types (long, specifically) and any incidental float results are re-cast to long as quickly as possible. Floating-point mode works equally well, it represents the numbers as doubles internally, but it is subject to the inaccuracies inherent in floating-point calculations.

createExpression(), THE power method!

Arguably MathEngine's most powerful method, and possibly that of MathTools itself, is createExpression(). This method takes as parameters a String variable name, a specially-formatted question template and a Knobs string. The template has a problem component, a calculation component, and an answer component. The Knobs are set first, converted to a String array, and filled into the calculation component. The calculation component is then broken down into individual calculations, which are fed into parseRPN() and the results placed into a String array starting at element 1. Element zero is set to the variable and this variable-and-calculation-result array is used as data for the Problem and Answer templates. These are then formed into a Question, assigned a unique ID, and returned.

This method allows very complex questions to be formulated with slots that can be filled with raw or calculated numbers. Although originally designed to simplify the generation of Order of Operations problems, this method is useful far, far beyond that. The indirection in the calculation component allows pre-formatting of computations, thus allowing true template generation of most types of algebraic equation-solving problems.

Arithmetic

The Arithmetic class encapsulates methods for manipulating numbers. Specifically, it deals with place values and their names. It is designed to provide tools for creating basic arithmetic problems. Its createNumber() method takes a formatting String and creates a number from the individual characters. Each digit can be specified literally or be taken from the following ranges: [0,9], [1,9], [5,9] and [0,4]. This allows easy creation of round-up/round-down problems. There is also a method to identify the name of a place value, with or without a whole or fractional suffix.

Arithmetic's true power method is toWords(). This method takes a long and translates it into words. I.e. calling Arithmetic.toWords('4567') returns the String 'four thousand five hundred sixty-seven'. Arithmetic also contains methods to turn a number into a digit-array and back.

Polynomial

The Polynomial class provides the machinery to create and manipulate integer-coefficient polynomials easily. It provides methods to add, subtract, and multiply Polynomials, both by integer constants and by other Polynomials. There are also presentation methods for formatting the Polynomial, evaluating it, and finding its derivative.

Once created a Polynomial is immutable, basically, but two aspects can be changed. The letter (String) used for the variable can be changed as can the name of the function, if it is printed using function notation. Most Polynomial-building methods revolve around the Polynomial Format: a String containing all information necessary to build the Polynomial. The String 'P:s:3 -5 8 2', for instance, creates a Polynomial P(s) = 3s3 - 5s2 + 8s + 2. The coefficients in the String are in descending order and are interpreted as such. One final creation method is createPolyKnobs(). It takes the function name and variable, but the coefficient component of the String is interpreted as a set of Knobs and is sent to MathEngine.setKnobs() to generate a Polynomial with random coefficients.

MFraction

The versatile MFraction class handles fractions for MathTools. The numerator and denominator are integral and the denominator cannot be zero (naturally!). MFraction itself provides ample constructors as well as static methods for creating more MFractions. Instances of MFraction are value-immutable, meaning once they are created they cannot change the actual value of the fraction around which they are created.

MFractions can be added, subtracted, multiplied, and divided. MFraction has methods for all of these plus methods to raise (multiply the numerator and denominator by the same thing) and reduce (divide the numerator and denominator by the same nonzero thing) themselves. There are methods for discovering each individual part of the fraction several different ways. The toDouble() method calculates the fraction's floating-point value and the equals() and compareTo() methods test MFractions for equality or position on a number line.

In addition to the manipulation methods, MFraction has very flexible formatting methods. The default format can be set for new MFractions and each MFraction instance can express itself as a constructor-style String, XML, MathML, or per a custom format. The formatting mechanism is Question.fillTemplate() with every aspect of the MFraction accessible as a specific replacement token. As far as creating MFractions, besides constructors built for fractions or mixed numbers, MFraction has a static method that will parse inline text-style expressions of fractions such as '1/4' or 7 3/5'.

MEquation and the Equation.TYPE_N enum

The MEquation class provides a quick and easy way to generate common algebra equations. It does not solve equations, rather, it presents them (and their solutions) in a test-ready format. The heart of the class is an enum holding the various types of equations available. Note: this list is by NO means exhaustive! It simply provides templates for equation types common to algebra equation-solving tests.

The Equation enum holds a collection of constants of the form 'TYPE_N' where N is a number. Each TYPE_ contains all the information needed to 'fill in' a particular form of equation, complete with solution, and to present this data in a consistent and easy to work with form. The term used for this is preformatting and, as implied by its name, it presents the data in a form that is easy to work with and change into whatever final format is required. The preformat format is 'Solution: A B C D... : BIRD' where 'Solution' is the solution to the equation, 'A B C...' is a space-separated String of numbers corresponding to letters in the equation itself and BIRD determines inequality reversal (see below).

Example: Equation.TYPE_400 is of the form 'Ax + B = C'. It requires three Knobs and preformats the String 'Sol:A B C:bird'. There is some indirection and 'under the hood' calculation between the Knobs and the placeholder values. So, suppose the Knobs for this equation were 2, 3, and 7. The calculations are carefully done to yield 'nice' answers, so the resulting String would be '2:3 7 13:false'. This yields the (filled-in) equation '3x + 7 = 13' with the solution 'x = 2' and no reversal required for an inequality..

Each TYPE_ contains four built-in presentation formats: Standard, OpenOffice, MathML and LaTeX. Standard format is exactly as the equation is written here. OpenOffice contains markup for the OpenOffice Equation Editor, MathML is MathML Presentation markup and LaTeX is for LaTeX typesetting technology. The MEquation class itself contains (static and instance) methods to produce Questions in all of these formats. This is the only nice-equation-generating method in the class! The (few!) other methods concern debugging and experimenting with the TYPE_ equations and getting a TYPE_ by its (int) number.

In addition to creating nice equations and inequalities, which is why this class was designed, it is also possible to generate nasty ones. The MEquation.Equation.solveFor() and the MEquation solveEquation() methods can be used to create and format TYPE_ equations that do not (necessarily) work out nicely. The values supplied, either as an int[] array or a Knobs String, are substituted in order for the placeholders and the equation's solution calculated. BIRD is indicated (String-returning method) or applied (Question-returning method).

As a matter of interest, MEquation can also generate inequalities. The formatting and preformatting methods all have a String for the relation to be used. Equality is the default but any String can be used. This can be problematic if the sense of an inequality needs to be reversed (multiplying or dividing by a negative number while solving). For this reason MEquation implements BIRD: Blind Inequality Reverse Detection. MEquation has NO knowledge or intelligence regarding the exact relation sent in (blind). Therefore it always assumes inequality and determines, based on the raw numbers used to build it, whether or not it should be reversed (inequality reverse detection). If so the BIRD value for the preformatting String will be 'true' and inequality reverse will be applied to the Answer part of any Question generated.

MathStat

MathStat offers an easy way to make, format and present common statistical calculations. It acts as an immutable container for up to two sets of data values. Its calculations include the mean, variance and standard deviation, both population and sample, for both data sets. In addition it can find the correlation coefficient and calculate simple linear regression values.

Format-wise MathStat offers every single calculation plus data set formatting as tokens in a pair of Question.fillTemplate()-based format() methods, one of which returns a String and the other a Question.

MathSet

The MathSet tool allows construction and presentation of set/subset questions. A MathSet instance allows set chains and trees of arbitrary size and complexity to be defined. Once defined, MathSet keeps track of the set-subset relationships and can be used to design questions containing random selection of either with a guaranteed-correct answer.

MathSet pre-defines the Real and Complex numbers along with a respectable number of formatting tokens, so set/subset problems involving those sets are very easy to put together.

MRadical

MRadical provides a way to handle radicals and radical expressions from a presentation standpoint. Once created, a MRadical is immutable, which allows them to be compared for equality, exact equality, and greater-than or less-than. The true power of the class is in its presentation methods. MRadical had built-in toMathML() and toXML() methods to represent it using MathML or MathTools XML.

MRadical's format() method provides many tokens in both raw and simplified form. If a radicand has a 'perfect-power' factor of its root, the greatest such is factored out and presented as a coefficient. This makes dealing with radicals truly easy and 'Simplify this radical...' problems almost trivial. Aditionally, the radical's double-value approximation is available both as a formatting token and via the toDouble() method.

MComplex

This class provides formatting and basic manipulation of imaginary and complex numbers. It is primarily a formatting method: the real and imaginary parts are kept as integer (int) values and not double but it is sufficient for basic imaginary/complex problems. The class itself provides an equals() method and several other condition-testing methods, such as isReal() and isZero() along with full access to every aspect of the number itself. Like MFraction and MRadical once a MComplex is created it is immutable and it does have a MathTools-XML representation.

Operation-wise MComplex provides methods to add, subtract, multiply and form a conjugate. It also provides a divide() method but, since this can involve non-integer values it is written as a formatting method. There is also a static method (and instance shadow), iPow() to raise 'i' to an arbitrary power.

In terms of presentation the format() method defines a rich set of replacement tokens, most of which concern the imaginary part, its sign and the symbol used to represent 'i'. By default the single letter 'i' is used to represent the imaginary number but it can be changed to any other letter or String; this allows formatting with technologies that have a special symbol or character sequence for 'i'. The class defines three formats internally: DEFAULT, STANDARD and TYPICAL. MComplex.FORMAT_DEFAULT always prints both components, even if one is zero. STANDARD is 'A + Bi' or 'A - Bi' even if A or B is zero. The TYPICAL format omits parts that are zero, including the middle sign and 'i' symbol if the imaginary part is zero.

MMatrix & Co.

MMatrix provides two things: a way to manipulate matrices mathematically and a way to present these matrices. MMatrices have methods to add, subtract, and multiply operation-compatible matrices as well as a scalar multiplication operation. There is also a method to calculate the determinant of a square matrix. Ancillary methods yield the number of rows or columns in the MMatrix, the order of the MMatrix as a String (e.g. '3x5'), and the MMatrix values as a double[][] array.

Once created a MMatrix is immutable but certain aspects can be changed. The core matrix (double[][] array of values) is never exposed directly and every MMatrix-yielding operation returns a new MMatrix. For generating systems of equations, though, the (names of the) variables used CAN be changed. Each MMatrix can be evaluated at specific values for each variable; the result of this is a one-dimensional (double[][]) array: an n-row, single column array.

Presentation-wise, MMatrix offers many formatting options. As a matrix, row- and column-separators can be specified, as can 'prefix' and 'suffix' Strings to be inserted before the actual matrix notation and afterward, respectively. System-of-equation formatting allows all of this AND row-specific relations! As with the MEquation class, MMatrix can also generate systems of inequailties.

MMatrixBuilder, the Sidekick

As powerful as it is, MMatrix only has three constructors. The zero-argument version is for exposing MMatrix to scripts. The second generates a MMatrix from a double[][] array and the third is a copy constructor.

Enter cox.jmatt.java.MathTools.util.MMatrixBuilder. MMatrixBuilder, also available in SCROB version, consists of (static) methods to turn various flavors of String into double[][] arrays. Each of these methods has a counterpart to generate MMatrices. MMatrixBuilder also has methods to generate from scratch various types of double[][] arrays: filled with a constant, square, and diagonal (square with one 'background' fill value and another for the main diagonal). And, since matrices are rectangular, with no 'ragged' rows, MMatrixBuilder also has the smoothCopy() method which takes any double[] array of double[] arrays and 'smooths the rough edges.' That is, it extends each row to the length of the longest and fills in any padded elements with zero.

The final utility in MMatrixBuilder is three methods to dump a double[][] array at Debug level, a MMatrix at debug level, and to print MMatrix information via CapCom.println(). For quickly generating a MMatrix to play with, the TEST_MATRIX() method generates a 3x3 MMatrix with rows '1 2 3', '4 5 6', and '7 8 9'.

Percent

The Percent class is an exercise in laziness. A Percent takes two of the three quantities that make up any application of percent and solves for the third. It contains quick-solve methods to solve with just the quantities and power-formatting methods for generating Questions.

MathXML

The MathXML class deals with formatting and presenting things in XML. Specifically, it deals with the MathML Presentation standard. Ir contains quick-and-easy methods for tag-wrapping <mrow>s, numbers, identifiers, and operations. It has two methods for generating <mfrac> tags and a very useful wrapTag() method that can generate any tag containing any (simple!) content. Rounding out the wrapping methods is wrapMath(), which wraps its content in <math> and </math> tags. This includes the 'xmlns=' attribute with the MathML URI.

The Swiss army knife of MathXML is its parseMathML() method. parseMathML() takes a String, optionally containing special formatting characters, and turns it into MathML markup. It automatically distinguishes between numbers, identifiers, and operators, and will replace '*' with the Unicode 'dot operator' and '/' with the Unicode 'division sign.'

The final general-utility method is escapeXML(), which replaces &, <, >, ", and ' with their respective Unicode escape sequences.