The aim of this document is to teach to MathCore new programmers, to the users of the library and to curious people, the basic structure and the main design of the entire module.
After you read this tutorial, you should be able to: navigate the code (and the documentation) to quickly find what you need; manipulate the math data created by MathCore; use MathCore commands and, eventually, extend them.
- Note:
- Sorry for my often erroneous english, but this is not my natural language :-)
Prerequisites
Conventions
Physical structure of the library
The library structure
Overview of main mcElementGUI, mcElementMath and mcElementIO functions
Further readings
Prerequisites
To understand this tutorial, you must meet two types of prerequisites: object-oriented programming in C++ and some basics about the libraries used by MathCore.
The C++ prerequisites consist in the concepts of:
- class
- inheritance
- virtual function
- polymorfism
About the libraries used, mapm, lua, tolua, underc, cint, iconv, libxml2 and especially wxWidgets, you should know only two main things:
-
what they are
-
why they are required
In fact, you will find that the usage of these libraries is limited to some very specific areas of MathCore library (except for some useful classes like wxString, wxPoint or wxDC, which are used almost everywhere).
Conventions
In this document (and more generally, in the entire MathCore documentation) I will use few conventions, which I list here:
-
with the word 'op' I mean 'operator': one of the mcOperator-derived classes (mcAddOp, mcSubOp, mcMultOp or mcDivOp) which are used to represent binary operations in the memory representation of math data .
-
All the classes begin with the 'mc' prefix and for member variables, a slightly modified Hungarian notation is used.
-
All the comments in the header files are written using Doxygen syntax (see the Documentation readme). Source files contain few comments inside the functions only: you should browse the header files if you want to read good docs.
-
With the word 'section', 'subsection' and 'helper class' I usually refer to one of the five parts (Data, GUI, Math, IO, Elem) which compose a mcElement-derived class (which will be explained later).
Physical structure of the library
The MathCore library is structured in various CPP and H files organized in the src and include/mc folders; see the main Readme file for more info about the module structure.
Anyway, the files can be distincted for their contents in three main categories:
Files containing mcElement-derived classes
| Files containing mcSolver-derived classes
| Files which implement special classes
(non mcElement-derived) | Files which implement MathCore interfaces
(the most important classes for library users) |
Bracket
Element
ElementArray
EmptyBox
ExpContainer
ExpElement
Fraction
Function
Text
Monomial
Number
Operator
OpTypes
Polynomial
Radical
Symbol
| Solver
PolySolver
BisectSolver
| MathHelpers
MathLine
MathUtils
MathMng
| MathCore
MathSystem |
Each file of MathCore follows some common rules: its name is the name of the class which defines or implements (except for some files which contain more than one definition/implementation) without the 'mc' suffix.
The files always begin with the LGPL disclaimer, then follows some file-specific information (author, creation date...), the precompiled-header stuff and last the implementation. For mcElement-derived classes there are, in order, the implementation of the element itself, its Data, GUI, Math and IO sections.
In the header files, after the disclaimer, an #ifdef - #endif block avoids more than one inclusion of the same header file in the CPP files. Then, there are the #includes of those headers required to correctly compile the class definition, the #defines of the values used by the classes and last, the class definitions.
The library structure
To understand the library structure, you must first know its aims: you can read for this purpose "MathCore general introduction".
Once you know that this library provides facilities both for math and import/export but also for graphical input/output, you should understand the need to divide the functions and variables associated with each one of these tasks.
Functions belonging to mcElement-derived classes (that is, classes which usually wrap mcElement features to hide MathCore internals) are organized in three great "blocks": GUI, math, IO, which follow the same naming-rules of mcElement-derived sections. Thus, for example, to use a GUI and an IO function of mcMathOrSystem, you just have to write something like:
That is, mcMathOrSystem implements a lot of functions with the same names of mcElementGUI, mcElementMath, mcElementIO functions, so it should be not too difficult to browse & use these MathCore special classes when you get used to the mcElement interface.
All mcElement-derived classes, instead, are composed up of five different classes, tied together, with the same name except for the suffix, which can be one of:
-
Data: this section contains all the varaibles common to the five parts of the mcElement-derived class and all the big structures which require a lot of memory, plus the functions which manipulate them.
-
GUI: here are grouped all the functions and variables used to render the elements on the screen, to move the cursor inside it by keyboard or mouse, the functions to select it and the functions which handle keyboard inputs. The most important variable which belongs to this section si the cursor position: it is used in a lot of GUI functions.
-
Math: all the functions which are used to perform math operations, ranging from basics to advanced, are grouped in this section. In some special cases, math functions are tied to GUI functions because they perform operations on selected elements only (and selection is performed through GUI functions), but generally, this section should be completely autonomous.
-
IO: this section contains all the import and export functions, which allow MathCore to save and load, for example, XHTML or XML files containing MathML (the web standard for math expressions) and inlined expressions (strings like "4x+5^(x-y)-sin(x_1)>=0").
-
[Elem]: this is the "glue" class. When this class is allocated, it automatically creates all the other four classes and link them together. So, a subsection of an element (e.g. mcFractionGUI, mcBracketIO, mcPolynomialMath...) should *never* be created alone; instead an instance of the related mcElement (e.g. mcFraction, mcBracket, mcPolynomial...) should be allocated, possibly through provided allocator functions (mcElement::NewElem, for example).
The mcElement-derived class which handles simple numbers, for example, is made up of mcNumberData, mcNumberGUI, mcNumberMath, mcNumberIO and mcNumber (the glue classes do not have any suffix, even if they are referred to as "elem").
To make easier the creation and the maintenance of all mcElement-derived classes (more than one hundred classes if we count also all the different sections), some macros are widely used (for further info on these ones, see Doxygen documentation):
mcDEFINE_HELPER_CLASSES()
#mcDEFINE_FRIEND_CLASSES()
|
Two useful macros which define all the classes associated with a mcElement-derived class. |
#mcDEFINE_ALLDATA_GETTERS()
#mcDEFINE_ALLGUI_GETTERS()
#mcDEFINE_ALLMATH_GETTERS()
#mcDEFINE_ALLIO_GETTERS()
#mcDEFINE_ALLELEM_GETTERS()
|
These macros are very important: they define the getters which are used in the various classes to access the other sections of the same element. The getters in total are 10: data(), gui(), math(), io(), hlp() and their const version (that is, functions with the same names returning const pointers).
A simple example could be:
void mcMyElem::gui_MyFnc() {
math_MultiplyBy(...);
data_DeepCopy(...);
io_GetMathML(...);
hlp()->GetId();
}
|
In conclusion, a mcElement-derived class is really composed of five helper classes, none of which can be created alone. In fact, the constructor of the glue classes (those derived directly by mcElement) creates immediately also the other four classes, hiding this task to the programmer.
However, this does not happen always: mcMathCore allows the user of the library, through the mcMathCore::Setup function to init only the GUI, the MATH or the IO systems (or a combination of them) of the library to save memory and processor time. If the sections which will be enabled are chosen at run-time, then you will need to write safe code:
mcNumber n(parent);
if (mcMathCore::isGUIEnabled()) n.gui_Draw(...);
if (mcMathCore::isMathEnabled()) n.math_MultiplyBy(...);
if (mcMathCore::isIOEnabled()) n.io_ImportPresentationMathML(...);
Overview of main mcElementGUI, mcElementMath and mcElementIO functions
mcElement provides a lot of functions, a wide abstract interface, which could be 'confusing' for the user who wants to use it. There are not too many main functions, but there are a lot of smaller methods which use them (before implementing a 'new' function, search for similar ones: many times I created functions that I found to be almost identic to the ready-made ones I coded some months before !). It's a Good Thing to have an idea of the main functions for the three main sections of each mcElement: this allows a faster search among the function lists (all the doxygen documentation is indispensable anyway !) and a better comprehension of the library.
mcElementGUI
-
All mcElementGUI output functions use the mcStyles facilities to render strings. A mcStyle class contains the mcTextSetting classes referring to all the types of mcElement-derived class and thus they contain the info to render any type of element. To each exponent level (in the expression a^b^c^d, the 'a' has exponent level zero, the 'b' has exponent level one, the 'c' an exponent level equal to two...) is associated a different mcStyle (each exponent level requires a smaller font of the previous one) which allow a great rendering flexibility (different fonts & colors can be chosen for different exponent levels and for different element types). mcElementGUI holds static pointers to a mcStyleArray which are usually setup by mcMathCore::Setup.
Anyway, mcStyle-access functions include some powerful functions like mcElementHelpers::sgui_SelectStyle or mcElementHelpers::sgui_GetSizeOf; also other functions, like mcElementHelpers::sgui_GetSize are strictly related to the current mcStyle selected.
-
mcElementHelpers::sgui_Draw is a simple but powerful function to render the elements on a given DC at a given position; obviously, container elements (like mcPolynomial, mcBracket...) when drawn, automatically call the gui_Draw() functions of their children. This function is also useful to give to the user a feedback, highlighting those elements placed below the mouse cursor.
-
Cursor-related functions are very important for mcElementGUI. To get the coords of the current cursor position just use the mcElementHelpers::sgui_GetRelCursorPos and to move the cursor in response to a user keypress, use mcElementHelpers::sgui_MoveCursor or mcElementHelpers::sgui_MoveCursorUsingPoint when moving it through the mouse.
-
User input is performed through the mcElementHelpers::sgui_Input function: this handles not only correct inputs, but also invalid keypress (generating syntax errors) and BACKSPACE and CANCEL keypress.
mcElementMath
[THIS SECTION IS NOT COMPLETE AND WILL CHANGE IN FUTURE]
-
CLASSIFICATION: since MathCore is designed to use different approaches for different types of problems, the mcElement::math_GetMathType function is very important to (roughtly) classify the type of data the engine must work on. See mcMathType for more info on the classification system currently used.
-
COMPARISON: it's very important for a CAS to know if something is mathematically equal to another one; it's also important to know if they are exactly identic (this check is performed by mcElement::math_CompareWith) or if they are just equivalent through some form of simplification (this check is performed by mcElement::math_hasSameContentOf).
-
EVALUATION: even if MathCore is a symbolic system, it still needs in some cases to evaluate an expression and get a numeric value (which can be an approximated value if the expression to evaluate involves periodic numbers or real constants, like PI); this is the task of mcElement::math_Evaluate.
-
SEARCHING: recursive search are performed by the mcElement::math_Find; this is important to get the coefficients of a polynomial equation, for example, or to classify the data...
-
SIMPLIFICATION/EXPANSION: these are very powerful functions whose objectives are, in order, make the data shorter and make the data longer. The 'lenght' of data is measured by the mcElement::math_GetLenght function. [TOWRITE]
-
BASIC OPERATIONS: basic operations are handled by two sets of functions. The first set, mcElement::math_Add, mcElement::math_MultiplyBy, mcElement::math_, mcElement::math_DivideBy return a mcBasicOpRes enumeration structure which can be a bit problematic to handle. The second set, mcElement::math_SimpleAdd, ..., is designed to make these functions easier (but they cannot be used always). All these functions are the raw-level edit functions for high-level math functions.
mcElementIO
-
MathCore has a good support for MathML both for input and output: the library user just have to load a document through the wxXml2 wrappers for the libxml2 library and then pass the MathML presentation root node to mcElement::io_ImportPresentationMathML. To export just use the mcElement::io_GetMathML.
-
Inlined expressions are those strings which are commonly used (and were used also above in this tutorial) to encode math data (which usually involves exponents, subscripts, special symbols...) with an ANSI sequence of inlined chars. MathCore uses the convention to use the '^' symbol to introduce exponents and the '_' symbol to introduce subscripts. This type of input and specially output is quite fast, through the mcElement::io_GetInlinedExpr and mcElement::io_ImportInlinedExpr functions.
[TOWRITE]
Further readings
If you want some further info about MathCore design you should read the "MathCore design" page which also explains the memory structure of math data.
There are no many docs yet on MathCore internals mainly because I am a programmer and I do not love to spend my time writing these documents :-), and also because the project is quite young (created the 9th September 2003). Anyway, if you stil have something unclear, please contact me at frm@users.sourceforge.net and I will be happy to discuss your questions.
Thanks for tolerating my bad english...
The author, Francesco Montorsi
Documentation generated with Doxygen on Sun Feb 6 17:13:19 2005 Visit MathStudio home page for more info |
[ Top ] |