AZ Dept. of Education Freethrows Product Part II

freethrows

In the previous post on this project, I discussed the general form of math problems that are generated in the Freethrows product, namely

W op X = Y op Z

where one of the variables is unknown and marked as such in the rendered equation.

I will provide a brief overview of the math engine architecture in this post.  The ‘math engine’ actually refers to a small number of libraries, some of which are non-mathematical in nature but are necessary in order to integrate the actual engine into the application.  These include

– Parsing Engine (parses and collates all math problems from the master data model into client-side value objects)

– Rendering Engine (renders an actual equation on screen given a generated-equation value object as a data provider)

– Actual math engine (computational engine that takes problem value objects as input and generates equations as output.  Also provides utilities for symbolic solution and analysis of problems)

A webservice call returns a list of problems and an implicit probability distribution of problem ids for a given game level.  The math engine parser works with either XML or raw ObjectProxy data and parses all server-supplied data into math problem value objects for the individual problems and a level structure that constructs the probability distribution of problem ids for a game level.  The engine exposes an API that allows the application to query a problem id for the current level.  That id is passed along to the math engine for generation.  The actual generation from the problem template is into a generated-problem value object.  This object may be passed as the data provider into the equation rendering engine.

Each constituent of an equation is generic and completely separated.  The Object hierarchy of these constituents is illustrated below.

me-1

Recall from the prior post that a ‘variable’ is actually a template from which a number of possible values of varying type may be generated.  Variables are maintained as generic templates inside the math engine.  A crude value type called a MathType is used to encapsulate actual values of variables. A MathType might hold any value from 5 to 15.76 to 3 5/8 .  Arithmetic operations may be performed on any math type.  Since MathTypes are completely generic (the math engine only requires that they implement an IMathType interface), it is possible to perform operations such as 1 + 2 3/4 and obtain the mixed-number math type 3 3/4 as the result.

MathTypes are created from variables using a Factory pattern.  Since rendering is completely divorced from problem representation and generation, TypeRenderers are used to render the numerical results of MathTypes into an application-specific container.  TypeRenderers are also created by a Factory.  OpRenderers are used to render operators.  The benefit of this approach is that if any changes are requested in how the division sign or how mixed numbers are rendered, the change is implemented only once inside the appropriate type or operation renderer.

An equation is represented by a value object that consists of expressions (left- and right-hand sides) and each expression consists of variables and operators.  The math engine either generates MathType values directly or passes the problem into an injectable constraint system to process all problem-wide constraints.  The result is a generated-problem value object consisting of a left- and right-hand side of MathTypes and operators.  This object is then passed to the rendering engine to render the equation.  Rendering is, of course, environment-specific.

The problem data model is sufficiently general to allow for different renderers for different problems.  Everything in the rendering engine is based on a default (horizontal layout, middle-aligned) equation renderer.  If the curriculum department wants a specific problem rendered in some other fashion, then the fully qualified class name of the appropriate renderer is provided in the data model for that problem.  The rendering engine uses reflection to instantiate the designated renderer at run-time.

In tomorrow’s post, I’ll cover some actual examples and discuss the problem analyzer product.

Comments are closed.