Lurch Deductive Engine

Class

MathConcept

The MathConcept class, an n-ary tree of MathConcept instances, using functions like parent() and children() to navigate the tree.

In many ways, this is an abstract base class. Yes, you can construct instances of it, and the test suite does so to verify that all the features herein work. But in actual applications, it will primarily (perhaps exclusively) be subclasses of this class that are instantiated. There are two such types of subclasses:

  1. LogicConcepts, which the LDE knows how to process for validating variable scoping and correctness of logical inference
  2. MathConcepts that are not merely logical, and thus can be arbitrarily complex (such as a chain of equations, or a set of exercises), but which can be broken down into many LogicConcepts algorithmically, for processing by the LDE. This algorithmic breakdown is implemented in the interpretation() function, which in this abstract base class returns simply an empty list, meaning "no LogicConcepts."

This second category of subclasses is not intended to be fully specified, but can grow and change over time, as new classes in that category are developed.

Constructor

new MathConcept(…children)

Create a new MathConcept. Any argument that is not a MathConcept is ignored.

Parameters

Source

Classes

MathConcept

Members

className

The name of this class, as a JavaScript string. For the MathConcept class, this is, of course, "MathConcept", but for subclasses, it will vary.

See the code initializing this member to see how subclasses should initialize their className members. This is used in deserialization, to correctly reconstitute objects of the appropriate class.

Source

IDs

We want the capability of assigning each MathConcept in a given hierarchy a globally unique ID. We therefore need a global place to store the mapping of IDs to instances, and thus we create this Map in the MathConcept class.

Each key in the map is an ID and the corresponding value is the instance with that ID. Each ID is a string.

This data structure should not be accessed by clients; it is private to this class. Use instanceWithID() and trackIDs() instead.

Source

subclasses

In order for a hierarchy of MathConcepts to be able to be serialized and deserialized, we need to track the class of each MathConcept in the hierarchy. We cannot reconstitute an object from its serialized state if we do not know which class to construct. So we track all subclasses of this class in a single static map, here.

This class and each of its subclasses should add themselves to this map and save the corresponding name in a static className variable in their class.

Source

Methods

static

addSubclass(name, classObject) → {string}

Adds a subclass to the static subclasses map tracked by this object, for use in reconsituting objects correctly from their serialized forms.

This method should be called once per subclass of MathConcept. To see how, see the code that initializes className.

Parameters

  • name string

    The name of the class, as it appears in code

  • classObject class

    The class itself, such as MathConcept, or any of its subclasses, that is, the JavaScript object used when constructing new instances.

Returns

  • string

    The value of the name parameter, for convenience in initializing each class's static className field

Source

static

feedback(feedbackData)

This implementation of the feedback function is a stub. It does nothing except dump the data to the console. However, it serves as the central method that all MathConcepts should use to transmit feedback, so that when this class is used in the LDE, which has a mechanism for transmitting feedback messages to its clients, the LDE can override this implementation with a real one, and all calls that use this central channel will then be correctly routed.

Documentation will be forthcoming later about the required form and content of the feedbackData parameter.

Parameters

  • feedbackData Object

    Any data that can be encoded using JSON.stringify() (or predictableStringify()), to be transmitted

Source

static

fromJSON(data) → {MathConcept}

Deserialize the data in the argument, producing a new MathConcept instance (or, more specifically, sometimes an instance of one of its subclasses).

Note that because this function is static, clients access it as MathConcept.fromJSON(...).

Parameters

  • data Object

    A JavaScript Object of the form produced by toJSON()

See

Returns

  • MathConcept

    A new MathConcept instance (which may actually be an instance of a proper subclass of MathConcept) as encoded in the given data

Source

static

fromSmackdown(string) → {Array.<MathConcept>}

MathConcept trees can be represented using a notation called "smackdown," which is a superset of the "putdown" notation used to represent LogicConcepts, as documented here. (Both of these are, of course, plays on the name of the famous format "markdown" by John Gruber.)

Smackdown supports all notation used in putdown (so readers may wish to begin learning about smackdown by following the link above to first learn about putdown) plus the following additional features:

  • The notation $...$ can be used to represent a LogicConcept, for example, $x^2-1$. The use of dollar signs is intentionally reminiscent of $\LaTeX$ notation for in-line math.
    • Note! $x^2-1$ is merely an example stating that mathematics of some sort can be placed between the dollar signs; it is not an indication that the specific notation x^2-1 is supported.
    • At present, no notation is supported, and any text between dollar signs is simply stored as a MathConcept instance with attribute "Interpret as" set to ["notation","X"], where X is the contents of the $...$ (without the dollar signs)---e.g., ["notation","x^2-1"].
    • We will later add support for defining custom mathematical notation for use in $...$ expressions, and then create a more robust way to interpret() MathConcept trees into LogicConcepts, which will parse such notation to create real expressions.
    • To include a literal $ inside a $...$ section, escape it as \$.
  • The notation \command{argument1}...{argumentN} is also intentionally reminiscent of $\LaTeX$ notation, and has an analogous meaning: some command applied to a sequence of $N$ arguments. For now, only the following commands are supported.
    • \begin{proof} and \end{proof} are replaced with { and }, respectively, so that they can be used to construct Environments, which is the meaning one would expect.
    • \label{X} is interpreted as if it were putdown notation for adding a JSON attribute to the preceding LogicConcept, associating the key "label" with the value X.
    • \ref{X} is exactly like the previous, but using attribute key "ref" instead of "label."
    • Any other command is stored as a MathConcept instance with attribute "Interpret as" having the form ["command",...], for example, \foo{bar}{baz} would become ["command","foo","bar","baz"].

The two notations given above will work hand-in-hand more over time. Specifically, we will create types of \commands that can define new notation to appear inside $...$ blocks.

For now, this routine fully supports parsing smackdown notation, but does not yet obey a robust set of commands, only those shown above.

Parameters

  • string string

    the smackdown code to be interpreted

Returns

  • Array.<MathConcept>

    an array of MathConcept instances, the meaning of the smackdown code provided as input

Source

static

instanceWithID(id) → {MathConcept}

Find a MathConcept instance from a given string ID. This assumes that the assignment of ID to MathConcept has been recorded in the global mapping in IDs, by the function trackIDs(). If it has not been so recorded, then this function will not find the instance and will return undefined.

Note that because this function is static, clients access it as MathConcept.instanceWithID("...").

Parameters

  • id string

    The MathConcept ID to look up

Returns

  • MathConcept

    The MathConcept that has the given ID, if any, or undefined if no MathConcept has the given ID

Source

static

typeAttributeKey(type) → {String}

Several functions internal to this object (isA(), asA(), and makeIntoA()) all take a type name as an argument, but do not use it directly as an attribute key, to avoid collisions among commonly used words. Rather, they use this function to slightly obfuscate the type name, thus making accidental name collisions less likely.

To give a specific example, if we wanted to designate a symbol as, say, a number, we might not want to set its attribute "number" to true, because some other piece of code might have a different meaning/intent for the common word "number" and might overwrite or misread our data. So for saying that a MathConcept is a number (or any other type), we use this function, which turns the text "number" into the text "_type_number", which almost no one would accidentally also use.

Parameters

  • type String

    The type that will be stored/queried using the resulting key

Returns

  • String

    The key to use for querying the given type

Source

accessibles(reflexive, inThis) → {Array.<MathConcept>}

The full contents of accessiblesIterator(), but put into an array rather than an iterator, for convenience, possibly at the cost of efficiency.

Parameters

Returns

  • Array.<MathConcept>

    All MathConcepts accessible to this one, with the latest (closest to this MathConcept) first, proceeding on to the earliest at the end of the array

Source

generator

accessiblesIterator(reflexive, inThis)

For a definition of accessibility, refer to the documentation for the isAccessibleTo() function.

In short, the accessibles of a node are its previous siblings, the previous siblings of its parent, the previous siblings of its grandparent, and so on, where each node yielded isLaterThan() all nodes yielded thereafter. You can limit the list to only those accessibles within a given ancestor by using the inThis parameter, documented below.

This function is a generator that yields each MathConcept accessible to this one, beginning with the one closest to this one (often its previous sibling) and proceeding back through the hierarchy, so that each new result is accessible to (and earlier than) the previous).

Parameters

  • reflexive boolean false

    Functions analogously to the reflexive parameter for isAccessibleTo(); that is, do we include this MathConcept on its list of accessibles? The default value is false.

  • inThis MathConcept null

    The container MathConcept in which to list accessibles. No accessible outside this ancestor will be returned. (If this is not actually an ancestor, it is ignored, and all accessibles are returned, which is the default.)

Source

address(ancestoropt) → {Array.<number>}

My address within the given ancestor, as a sequence of indices [i1,i2,...,in] such that ancestor.child(i1).child(i2)....child(in) is this MathConcept.

This is a kind of inverse to index().

Parameters

  • ancestor MathConcept <optional>

    The ancestor in which to compute my address, which defaults to my highest ancestor. If this argument is not actually an ancestor of this MathConcept, then we treat it as if it had been omitted.

Returns

  • Array.<number>

    An array of numbers as described above, which will be empty in the degenerate case where this MathConcept has no parent or this MathConcept is the given ancestor

Source

generator

ancestorsIterator()

An iterator through all the ancestors of this MathConcept, starting with itself as the first (trivial) ancestor, and walking upwards from there.

This function is a generator that yields this MathConcept, then its parent, grandparent, etc.

Source

ancestorsSatisfying(predicate) → {Array.<MathConcept>}

Find all ancestors of this MathConcept satisfying the given predicate. Note that this MathConcept counts as a trivial ancestor of itself, so if you don't want that, modify your predicate to exclude it.

Parameters

  • predicate function

    Predicate to evaluate on each ancestor

Returns

  • Array.<MathConcept>

    The ancestors satisfying the predicate, which may be an empty array

Source

attr(attributes) → {MathConcept}

Add attributes to a MathConcept and return the MathConcept. This function is a convenient form of repeated calls to setAttribute(), and returns the MathConcept for ease of use in method chaining.

Example use: const S = new MathConcept().attr( { k1 : 'v1', k2 : 'v2' } )

Because this calls setAttribute() zero or more times, as dictated by the contents of attributes, it may result in multiple firings of the events willBeChanged and wasChanged.

Parameters

  • attributes Object | Map | Array

    A collection of key-value pairs to add to this MathConcept's attributes. This can be a JavaScript Object, with keys and values in the usual {'key':value,...} form, a JavaScript Map object, or a JavaScript Array of key-value pairs, of the form [['key',value],...]. If this argument is not of any of these three forms (or is omitted), this function does not add any attributes to the MathConcept.

Returns

  • MathConcept

    The MathConcept itself, for use in method chaining, as in the example shown above.

Source

binds() → {boolean}

By default, MathConcepts do not bind symbols. Subclasses of MathConcept may import the BindingInterface and therefore override the following function, but in the base case, it simply returns false to indicate that no symbols are bound.

See

Returns

  • boolean

    the constant false

Source

changeID(newID) → {boolean}

If a MathConcept wishes to change its ID, then we may need to update the internal IDs mapping. The following function changes the ID and updates that mapping if needed all in one action, to make it easy for the client to change a MathConcept's ID, just by calling this function.

If for some reason the change was not possible, then this function will take no action and return false. Possible reasons include:

  • the old ID isn't tracked in the IDs mapping
  • the new ID is already associated with another MathConcept
  • the new ID is the same as the old ID

This function also updates other MathConcepts that connect to this one, changing their connections to use this MathConcept's new ID, so that all connections are preserved across the use of this function.

Parameters

  • newID string

    The ID to use as the replacement for this MathConcept's existing ID. It will be treated as a string if it is not already one.

Returns

  • boolean

    True if the operation succeeded, false if it could not be performed (and thus no action was taken)

Source

child(i) → {MathConcept}

Get the child of this MathConcept at index i.

If the index is invalid (that is, it is anything other than one of {0,1,...,n-1} if there are n children) then undefined will be returned instead.

Parameters

  • i number

    The index of the child being fetched

Returns

  • MathConcept

    The child at the given index, or undefined if none

Source

childrenSatisfying(predicate) → {Array.<MathConcept>}

The list of children of this MathConcept that satisfy the given predicate, in the same order that they appear as children. Obviously, not all children may be included in the result, depending on the predicate.

Parameters

  • predicate function

    The predicate to use for testing children

Returns

  • Array.<MathConcept>

    The array of children satisfying the given predicate

Source

clearAttributes(…keys)

For details on how MathConcepts store attributes, see the documentation for the getAttribute() function.

This function removes zero or more key-value pairs from the MathConcept's attribute dictionary. See the restrictions on keys and values in the documentation linked to above.

The change events are fired only if the given keys are actually currently in use by some key-value pairs in the MathConcept. If you pass multiple keys to be removed, each will generate a separate pair of willBeChanged and wasChanged events.

Parameters

  • keys Array <repeatable>

    The list of keys indicating which key-value pairs should be removed from this MathConcept; each of these keys must be a string, or it will be converted into one; if this parameter is omitted, it defaults to all the keys for this MathConcept's attributes

Fires

Source

clearIDs(recursive)

Remove the ID of this MathConcept and, if requested, all of its descendants. This does not change anything about the global IDs mapping, so if this MathConcept's IDs are tracked, you should call untrackIDs() first.

Because connections use the ID system, any connections that this MathConcept is a part of will also be severed, by a call to removeConnections().

Parameters

  • recursive boolean true

    Whether to clear IDs from all descendants of this MathConcept as well

Source

connectTo(target, connectionID, data) → {Connection}

Connect this MathConcept to another, called the target, optionally attaching some data to the connection as well. This function just calls Connection.create(), and is thus here just for convenience.

Parameters

  • target MathConcept

    The target of the new connection

  • connectionID string

    The unique ID to use for the new connection we are to create

  • data * null

    The optional data to attach to the new connection. See the create() function in the Connection class for the acceptable formats of this data.

Returns

  • Connection

    A Connection instance for the newly created connection between this MathConcept and the target. This return value can be safely ignored, because the connection data is stored in the source and target MathConcepts, and is not dependent on the Connection object itself. However, the return value will be false if the chosen connection ID is in use or if this MathConcept or the target does not pass idIsTracked().

Source

copy() → {MathConcept}

A deep copy of this MathConcept. It will have no subtree in common with this one, and yet it will satisfy an equals() check with this MathConcept.

In order to ensure that the copy has the same class as the original (even if that is a proper subclass of MathConcept), this function depends upon that subclass's having registered itself with the subclasses static member.

Returns

  • MathConcept

    A deep copy

Source

copyAttributesFrom(mathConcept) → {MathConcept}

Copy all the attributes from another MathConcept instance to this one. The attributes are copied deeply, so that if the values are arrays or objects, they are not shared between the two MathConcepts. The attributes are copied using attr(), which calls setAttribute() on each key separately, thus possibly generating many pairs of willBeChanged and wasChanged events.

If this MathConcept shares some attribute keys with the one passed as the parameter, the attributes of mathConcept will overwrite the attributes already in this object.

Parameters

  • mathConcept MathConcept

    another MathConcept instance from which to copy all of its attributes

Returns

  • MathConcept

    this object, for method chaining, as in attr()

Source

descendantsSatisfying(predicate) → {Array.<MathConcept>}

An array of those descendants of this MathConcept that satisfy the given predicate. These are not copies, but the actual descendants; if you alter one, it changes the hierarchy beneath this MathConcept.

Note that this MathConcept counts as a descendant of itself. To exclude this MathConcept from consideration, simply change your predicate, as in X.descendantsSatisfying( d => X != d && predicate(d) ).

Parameters

  • predicate function

    The predicate to use for testing descendants

Returns

  • Array.<MathConcept>

    A list of descendants of this MathConcept, precisely those that satisfy the given predicate, listed in the order they would be visited in a depth-first traversal of the tree

Source

equals(other) → {boolean}

Whether this MathConcept is structurally equal to the one passed as parameter. In particular, this means that this function will return true if and only if all the following are true.

  • other is an instance of the MathConcept class
  • other has the same set of attribute keys as this instance
  • each of those keys maps to the same data in each instance (where comparison of attribute values is done by JSON.equals())
  • other has the same number of children as this instance
  • each of other's children passes a recursive equals() check with the corresponding child of this instance

Parameters

See

Returns

  • boolean

    true if and only if this MathConcept equals other

Source

feedback(feedbackData)

Send feedback on this particular MathConcept instance. This takes the given feedback data, adds to it the fact that this particular instance is the subject of the feedback (by using its id(), and then asks the static feedback() function to send that feedback to the LDE.

Parameters

  • feedbackData Object

    Any data that can be encoded using JSON.stringify() (or predictableStringify()), to be transmitted

Source

freeSymbolNames() → {Array.<string>}

A Symbol X is free in an ancestor Y if and only if no MathConcept that is an ancestor A of X inside of (or equal to) Y satisfies A.binds( X.text() ). This function returns an array of all symbol names that appear within this MathConcept and, at the point where they appear, are free in this ancestor MathConcept.

If, instead of just the names of the symbols, you wish to have the Symbol instances themselves, you can couple the isFree() function with the descendantsSatisfying() function to achieve that.

Returns

  • Array.<string>

    an array of names of free symbols appearing as descendants of this MathConcept

Source

getAttribute(key, defaultValue) → {*}

Every MathConcept stores a dictionary of attributes as key-value pairs. All keys should be strings (or they will be converted into strings) and their associated values must be amenable to a JSON encoding.

This function looks up and returns the value of an attribute in this MathConcept, the one with the given key.

Parameters

  • key *

    name of the attribute to look up

  • defaultValue *

    the value that should be returned if the key does not appear as the name of an attribute in this MathConcept (defaults to undefined)

Returns

  • *

    the value associated with the given key

Source

getAttributeKeys() → {Array}

Get the list of keys used in the attributes dictionary within this MathConcept. For more details on the MathConcept attribution system, see the documentation for getAttribute().

Each key must be atomic and will be converted into a string if it is not already one.

Returns

  • Array

    A list of values used as keys

Source

hasAttribute(key)

Whether this MathConcept has an attribute with the given key. For more details on the MathConcept attribution system, see the documentation for getAttribute().

Parameters

  • key *

    name of the attribute to look up; this should be atomic and will be converted into a string if it is not already one

Source

hasChildSatisfying(predicate) → {boolean}

Whether this MathConcept has any children satisfying the given predicate. The predicate will be evaluated on each child in order until one passes or all fail; it may not be evaluated on all children, if not needed.

Parameters

  • predicate function

    The predicate to use for testing children

Returns

  • boolean

    True if and only if some child satisfies the given predicate

Source

hasDescendantSatisfying(predicate) → {boolean}

Whether this MathConcept has any descendant satisfying the given predicate. The predicate will be evaluated on each descendant in depth-first order until one passes or all fail; it may not be evaluated on all descendants, if not needed.

Note that this MathConcept counts as a descendant of itself. To ignore this MathConcept, simply change the predicate to do so, as in X.descendantsSatisfying( d => X != d && predicate(d) ).

Parameters

  • predicate function

    The predicate to use for testing descendants

Returns

  • boolean

    True if and only if some descendant satisfies the given predicate

Source

ID() → {string}

The ID of this MathConcept, if it has one, or undefined otherwise. An ID is always a string; this is ensured by the setId() function.

See

  • setID()

Returns

  • string

    The ID of this MathConcept, or undefined if there is none

Source

idIsTracked() → {boolean}

Check whether this MathConcept's ID is currently tracked and associated with this MathConcept itself.

Returns

  • boolean

    Whether the ID of this MathConcept is currently tracked by the global IDs mapping and that it is associated, by that mapping, with this MathConcept

Source

index(address) → {MathConcept}

Performs repeated child indexing to find a specific descendant. If the address given as input is the array [i1,i2,...,in], then this returns this.child(i1).child(i2)....child(in).

If the given address is the empty array, the result is this MathConcept.

This is a kind of inverse to address().

Parameters

  • address Array.<number>

    A sequence of nonnegative indices, as described in the documentation for address()

Returns

  • MathConcept

    A descendant MathConcept, following the definition above, or undefined if there is no such MathConcept

Source

indexInParent() → {number}

Returns the value i such that this.parent().child(i) is this object, provided that this MathConcept has a parent.

Returns

  • number

    The index of this MathConcept in its parent's children list

Source

insertChild(child, atIndex)

Insert a child into this MathConcept's list of children.

Any children at the given index or later will be moved one index later to make room for the new insertion. The index can be anything from 0 to the number of children (inclusive); this last value means insert at the end of the children array. The default insertion index is the beginning of the array.

If the child to be inserted is an ancestor of this MathConcept, then we remove this MathConcept from its parent, to obey the insertion command given while still maintaining acyclicity in the tree structure. If the child to be inserted is this node itself, this function does nothing.

Parameters

  • child MathConcept

    the child to insert

  • atIndex number 0

    the index at which the new child will be

Fires

Source

interpret() → {LogicConcept}

This function is a temporary placeholder. Later, a sophisticated interpretation mechanism will be developed to convert a user's representation of their document into a hierarchy of LogicConcept instances.

(In fact, we will actually use the interpret() function when we do so, and remove this one. That one is the official permanent interpretation API.)

For now, we have this simple version in which many features are not yet implemented. Its behavior is as follows.

  1. The method of interpretation that should be followed is extracted from the "Interpret as" attribute of this object. If there is no such attribute, an error is thrown. The attribute value should be an array, call it $[a_1,\ldots,a_n]$, where $a_1$ is the method of interpretation and each other $a_i$ is some parameter to it.
  2. If $a_1$ is "class" then $a_2$ must be the name of some subclass of LogicConcept, and this routine will contruct a new instance of that class, copy all this object's attributes to it, and give it a children list built by recursively interpreting this MathConcept's children.
  3. If $a_1$ is "notation" or "command" then a single Symbol will be created whose text content states that support for interpreting the notation or command in question has not yet been implemented.
  4. If $a_1$ is anything else, an error is thrown.

See

Returns

  • LogicConcept

    the meaning of this MathConcept, subject to the limitations documented above

Source

interpretation() → {Array.<LogicConcept>}

Any MathConcept can be interpreted, which means converting its high-level concepts into lower-level concepts that are only logical. For example, in mathematics, we my write A=B=C, but logically, this is two separate statements, A=B and B=C.

The interpretation function defined here can be used by any subclass to implement its specific means of interpretation of mathematical concepts into logical ones. In this abstract base class, the default is simply to return an empty list, meaning "no logic concepts." Subclasses should override this with an implementation specific to their actual mathematical meaning.

Returns

  • Array.<LogicConcept>

    The ordered list of LogicConcepts whose combined meaning is equal to the meaning of this MathConcept

Source

isA(type) → {boolean}

MathConcepts can be categorized into types with simple string labels. For instance, we might want to say that some MathConcepts are assumptions, and flag that using an attribute. Some of these attributes have meanings that may be respected by methods in this class or its subclasses, but the client is free to use any type names they wish. A MathConcept may have zero, one, or more types.

This convenience function, together with makeIntoA() and asA(), makes it easy to use the MathConcept's attributes to store such information.

Note that the word "type" is being used in the informal, English sense, here. There is no intended or implied reference to mathematical types, variable types in programming languages, or type theory in general. This suite of functions is for adding boolean flags to MathConcepts in an easy way.

Parameters

  • type string

    The type we wish to query

Returns

  • boolean

    Whether this MathConcept has that type

Source

isAccessibleTo(other, reflexive) → {boolean}

In computer programming, the notion of variable scope is common. A line of code can "see" a variable (or is in the scope of that variable) if it appears later than the variable's declaration and at a deeper level of block nesting. We have the same concept within MathConcepts, and we call it both "scope" and "accessibility." We say that any later MathConcept is "in the scope of" an earlier one, or equivalently, the earlier one "is accessible to" the later one, if the nesting of intermediate MathConcepts permits it in the usual way.

More specifically, a MathConcept X is in the scope of precisely the following other MathConcepts: all of X's previous siblings, all of X.parent()'s previous siblings (if X.parent() exists), all of X.parent().parent()'s previous siblings (if X.parent().parent() exists), and so on. In particular, a MathConcept is not in its own scope, nor in the scope of any of its other ancestors.

The one exception to what's stated above is the reflexive case, whether X.isAccessibleTo(X). By default, this is false, because we typically think of X.isAccessibleTo(Y) as answering the question, "Can Y justify itself by citing X?" and we do not wish that relation to be reflexive. However, X.isInTheScopeOf(X) would typically be considered true, because a variable declaration is the beginning of the scope of that variable. So we provide the second parameter, reflexive, for customizing this behavior, and we have that, for any boolean value b, X.isAccessibleTo(Y,b) if and only if Y.isInTheScopeOf(X,b).

Parameters

  • other MathConcept

    The MathConcept to which we're asking whether the current one is accessible. If this parameter is not a MathConcept, the result is undefined.

  • reflexive boolean false

    Whether the relation should be reflexive, that is, whether it should judge X.isAccessibleTo(X) to be true.

Returns

  • boolean

    Whether this MathConcept is accessible to other.

Source

isAtomic() → {boolean}

A MathConcept is atomic if and only if it has no children. Thus this is a shorthand for S.numChildren() == 0.

Returns

  • boolean

    Whether the number of children is zero

Source

isDirty() → {boolean}

Getter for the "dirty" flag of this MathConcept. A MathConcept may be marked dirty by the client for any number of reasons. For instance, if a MathConcept changes and thus needs to be reprocessed (such as interpreted or validated) to reflect those most recent changes, it may be marked dirty until such processing takes place.

MathConcept instances are constructed with their dirty flag set to false.

Returns

  • boolean

    Whether this MathConcept is currently marked dirty

Source

isEarlierThan(other) → {boolean}

Under pre-order tree traversal, which of two MathConcept comes first? We call the first "earlier than" the other MathConcept, because we will use MathConcept hierarchies to represent documents, and first in a pre-order tree traversal would then mean earlier in the document.

Note that this is a strict ordering, so a MathConcept is not earlier than itself.

Parameters

  • other MathConcept

    The MathConcept with which to compare this one. (The result is undefined if this is not a MathConcept.)

Returns

  • boolean

    Whether this MathConcept is earlier than the other, or undefined if they are incomparable (not in the same tree)

Source

isFree(inThisopt) → {boolean}

Is this MathConcept free in one of its ancestors? If the ancestor is not specified, it defaults to the MathConcept's topmost ancestor. Otherwise, you can specify it with the parameter.

A MathConcept is free in an ancestor if none of the MathConcept's free identifiers are bound within that ancestor.

Note the one rare corner case that the head of a binding (even if it is a compound expression) is not bound by the binding. For instance, if we have an expression like $\sum_{i=a}^b A_i$, then $i$ is bound in $A_i$, but not in either $a$ or $b$, which are part of the compound head symbol, written in LISP notation something like ((sum a b) i (A i)). This corner case rarely arises, because it would be very confusing for $i$ to appear free in either $a$ or $b$, but is important to document.

Parameters

  • inThis MathConcept <optional>

    The ancestor in which the question takes place, as described above

See

Returns

  • boolean

    Whether this MathConcept is free in the specified ancestor (or its topmost ancestor if none is specified)

Source

isFreeToReplace(original, inThisopt) → {boolean}

A MathConcept A is free to replace a MathConcept B if no identifier free in A becomes bound when B is replaced by A.

Parameters

  • original MathConcept

    The MathConcept to be replaced with this one

  • inThis MathConcept <optional>

    The ancestor we use as a context in which to gauge bound/free identifiers, as in the inThis parameter to isFree(). If omitted, the context defaults to the top-level ancestor of original.

See

Returns

  • boolean

    True if this MathConcept is free to replace original, and false if it is not.

Source

isInTheScopeOf(other, reflexive) → {boolean}

A full definition of both isAccessibleTo() and isInTheScopeOf() appears in the documentation for isAccessibleTo(). Refer there for details.

Parameters

  • other MathConcept

    The MathConcept in whose scope we're asking whether this one lies. If this parameter is not a MathConcept, the result is undefined.

  • reflexive boolean true

    Whether the relation should be reflexive, that is, whether it should judge X.isInTheScopeOf(X) to be true.

Returns

  • boolean

    Whether this MathConcept is in the scope of other.

Source

isLaterThan(other) → {boolean}

This is the opposite of isEarlierThan(). We have A.isLaterThan(B) if and only if B.isEarlierThan(A). This is therefore just a convenience function.

Parameters

  • other MathConcept

    The MathConcept with which to compare this one. (The result is undefined if this is not a MathConcept.)

Returns

  • boolean

    Whether this MathConcept is later than the other, or undefined if they are incomparable (not in the same tree)

Source

makeIntoA(type) → {MathConcept}

For a full explanation of the typing features afforded by this function, see the documentation for isA().

This function adds the requested type to the MathConcept's attributes and returns the MathConcept itself, for use in method chaining, as in S.makeIntoA( 'fruit' ).setAttribute( 'color', 'green' ).

Parameters

  • type string

    The type to add to this MathConcept

Returns

  • MathConcept

    This MathConcept, after the change has been made to it

Source

markDirty(onopt, propagateopt)

Setter for the "dirty" flag of this MathConcept. For information on the meaning of the flag, see isDirty().

Parameters

  • on boolean <optional>
    true

    Whether to mark it dirty (true) or clean (false). If this value is not boolean, it will be converted to one (with the !! idiom).

  • propagate boolean <optional>

    Whether to propagate the change upwards to parent MathConcepts. By default, this happens if and only if the on member is true, so that dirtiness propagates upwards, but cleanness does not. This is appropriate because when a child needs reprocessing, this often requires reprocessing its parent as well, but when a child has been reprocessed, its parent may still need to be.

See

Source

nextInTree() → {MathConcept}

Finds the next node in the same tree as this one, where "next" is defined in terms of a pre-order tree traversal. If there is no such node, this will return undefined.

Therefore this function also returns the earliest node later than this one, in the sense of isEarlierThan() and isLaterThan().

For example, in a parent node with several atomic children, the next node of the parent is the first child, and the next node of each child is the one after, but the last child has no next node.

Returns

  • MathConcept

    The next node in pre-order traversal after this one

Source

occursFree(concept, inThisopt) → {boolean}

Does a copy of the given MathConcept concept occur free anywhere in this MathConcept? More specifically, is there a descendant D of this MathConcept such that D.equals( concept ) and D.isFree( inThis )?

Parameters

  • concept MathConcept

    This function looks for copies of this MathConcept

  • inThis MathConcept <optional>

    The notion of "free" is relative to this MathConcept, in the same sense of the inThis parameter to isFree()

Returns

  • boolean

    True if and only if there is a copy of concept as a descendant of this MathConcept satisfying .isFree( inThis )

Source

generator

preOrderIterator(inThisTreeOnly)

An iterator that walks through the entire tree from this node onward, in a pre-order tree traversal, yielding each node in turn.

This function is a generator that yields the next node after this one in pre-order tree traversal, just as nextInTree() would yield, then the next after that, and so on.

Parameters

  • inThisTreeOnly boolean true

    Set this to true to limit the iterator to return only descendants of this MathConcept. Set it to false to permit the iterator to proceed outside of this tree into its context, once all nodes within this tree have been exhausted. If this MathConcept has no parent, then this parameter is irrelevant.

Source

preOrderTraversal(inThisTreeOnly) → {Array.<MathConcept>}

The same as preOrderIterator(), but already computed into array form for convenience (usually at a cost of efficiency).

Parameters

Returns

  • Array.<MathConcept>

    The array containing a pre-order tree traversal starting with this node, beginning with nextInTree(), then the next after that, and so on.

Source

previousInTree() → {MathConcept}

Finds the previous node in the same tree as this one, where "previous" is defined in terms of a pre-order tree traversal. If there is no such node, this will return undefined.

Therefore this function also returns the latest node earlierr than this one, in the sense of isEarlierThan() and isLaterThan().

This is the reverse of nextInTree(), in the sense that X.nextInTree().previousInTree() and X.previousInTree().nextInTree() will, in general, be X, unless one of the computations involved is undefined.

Returns

  • MathConcept

    The previous node in pre-order traversal before this one

Source

pushChild(child)

Append a new child to the end of this MathConcept's list of children. This is equivalent to a call to insertChild() with the length of the current children array as the index at which to insert.

Parameters

Source

removeConnections()

Remove all connections into or out of this MathConcept. This deletes the relevant data from this MathConcept's attributes as well as those of the MathConcepts on the other end of each connection. For documentation on the data format for this stored data, see the Connection class.

This function simply runs remove() on every connection in getConnections().

Source

replaceFree(original, replacement, inThisopt)

Consider every free occurrence of original within this MathConcept, and replace each with a copy of replacement if and only if replacement is free to replace that instance. Each instance is judged separately, so there may be any number of replacements, from zero up to the number of free occurrences of original.

Parameters

  • original MathConcept

    Replace copies of this MathConcept with copies of replacement

  • replacement MathConcept

    Replace copies of original with copies of this MathConcept

  • inThis MathConcept <optional>

    When judging free/bound identifiers, judge them relative to this ancestor context, in the same sense of the inThis parameter to isFree()

See

Source

replaceWith(other)

Replace this MathConcept, exactly where it sits in its parent MathConcept, with the given one, thus deparenting this one.

For example, if A is a child of B and we call B.replaceWith(C), then C will now be a child of A at the same index that B formerly occupied, and B will now have no parent. If C had a parent before, it will have been removed from it (thus decreasing that parent's number of children by one).

Parameters

  • other MathConcept

    the MathConcept with which to replace this one

Source

scope(reflexive) → {Array.<MathConcept>}

The full contents of scopeIterator(), but put into an array rather than an iterator, for convenience, possibly at the cost of efficiency.

Parameters

  • reflexive boolean true

    Passed directly to scopeIterator(); see that function for more information

Returns

  • Array.<MathConcept>

    All MathConcepts in the scope of to this one, with the earliest (closest to this MathConcept) first, proceeding on to the latest at the end of the array

Source

generator

scopeIterator(reflexive)

For a definition of scope, refer to the documentation for the isAccessibleTo() function.

In short, the scope of a node is itself, all of its later siblings, and all their descendants, where each node yielded by the iterator isEarlierThan() all nodes yielded thereafter.

This function is a generator that yields each MathConcept in the scope of this one, beginning with the one closest to this one (often its previous sibling) and proceeding forward through the hierarchy, so that each new result isLaterThan() the previous.

Parameters

  • reflexive boolean true

    Functions analogously to the reflexive parameter for isInTheScopeOf(); that is, do we include this MathConcept on its list of things in its scope? The default value is true.

Source

setAttribute(key, value)

For details on how MathConcepts store attributes, see the documentation for the getAttribute() function.

This function stores a new key-value pair in the MathConcept's attribute dictionary. See the restrictions on keys and values in the documentation linked to above. Calling this function overwrites any old value that was stored under the given key.

The change events are fired only if the new value is different from the old value, according to JSON.equals().

Parameters

  • key *

    The key that indexes the key-value pair we are about to insert or overwrite; this must be a string or will be converted into one

  • value *

    The value to associate with the given key; this must be a JavaScript value amenable to JSON encoding

See

Fires

Source

setChildren(children)

Replace the entire children array of this MathConcept with a new one.

This is equivalent to removing all the current children of this MathConcept in order from lowest index to highest, then inserting all the children in the given array, again from lowest index to highest.

The intent is not for any of the elements of the given array to be ancestors or descendants of one another, but even if they are, the action taken here still follows the explanation given in the previous paragraph.

Parameters

Source

setID(id)

Set the ID of this MathConcept. Note that this does not change the global tracking of IDs, because one could easily call this function to assign an already-in-use ID. To ensure that the IDs in a hierarchy are tracked, call trackIDs(), and if that has already been called, then to change a MathConcept's ID assignment, call changeID().

Parameters

  • id string

    The new ID to assign. If this is not a string, it will be converted into one.

Source

toJSON(includeIDs) → {Object}

Convert this object to JavaScript data ready for JSON serialization. Note that the result of this function is not a string, but is ready to be converted into one through JSON.stringify() or (preferably), predictableStringify().

The resulting object has some of its attributes directly re-used (not copied) from within this MathConcept (notably the values of many attributes), for the sake of efficiency. Thus you should not modify the contents of the returned MathConcept. If you want a completely independent copy, call JSON.copy() on the return value.

The particular classes of this MathConcept and any of its children are stored in the result, so that a deep copy of this MathConcept can be recreated from that object using fromJSON().

If the serialized result will later be deserialized after the original has been destroyed, then you may wish to preserve the unique IDs of each MathConcept in the hierarchy in the serialization. But if the original will still exist, you may not. Thus the parameter lets you choose which of these behaviors you need. By default, IDs are included.

Parameters

  • includeIDs boolean true

    Whether to include the IDs of the MathConcept and its descendants in the serialized form (as part of the MathConcept's attributes)

See

  • fromJSON()
  • subclasses

Returns

  • Object

    A serialized version of this MathConcept

Source

toSmackdown() → {string}

This function reverses the operation of fromSmackdown(). It requires this MathConcept to be of the particular form created by that function; it cannot operate on arbitrary MathConcepts, because not all can be represented by smackdown notation. (For instance, a MathConcept created by a call to new MathConcept() is too vague to be representable using smackdown notation.)

Returns

  • string

    smackdown notation for this MathConcept

Source

toString() → {string}

A simple string representation that represents any MathConcept using an S-expression (that is, (a b c ...)) of the string representations of its children. This produces LISP-like results, although they will contain only parentheses if all are MathConcept instances. But subclasses can override this method to specialize it.

See

Returns

  • string

    A simple string representation

Source

trackConnections() → {boolean}

There are some situations in which a MathConcept hierarchy will have data in it about connections, and yet those connections were not created with the API in the Connections class. For example, if a MathConcept hierarchy has been saved in serialized form and then deserialized at a later date. Thus we need a way to place into the IDs member of the Connection class all the IDs of the connections in any given MathConcept hierarchy. This function does so. In that way, it is very similar to trackIDs().

Connections are processed only at the source node, so that we do not process each one twice. Thus any connection into this MathConcept from outside will not be processed by this function, but connections from this one out or among this one's descendants in either direction will be processed.

Returns

  • boolean

    True if and only if every connection ID that appers in this MathConcept and its descendants was able to be added to the global mapping in IDs. If any fail (because the ID was already in use), this returns false. Even if it returns false, it still adds as many connections as it can to that global mapping.

Source

trackIDs(recursive)

Store in the global IDs mapping the association of this MathConcept's ID with this MathConcept instance itself. If the parameter is set to true (the default), then do the same recursively to all of its descendants.

Calling this function then enables you to call instanceWithID() on any of the IDs of a descendant and get that descendant in return. Note that this does not check to see if a MathConcept with the given ID has already been recorded; it will overwrite any past data in the IDs mapping.

This function also makes a call to trackConnections(), because IDs are required in order for connections to exist, and enabling IDs almost always coincides with enabling connections as well.

Important: To prevent memory leaks, whenever a MathConcept hierarchy is no longer used by the client, you should call untrackIDs() on it.

Parameters

  • recursive boolean true

    Whether to recursively track IDs of all child, grandchild, etc. MathConcepts. (If false, only this MathConcept's ID is tracked, not those of its descendants.)

Source

transferConnectionsTo(recipient)

When replacing a MathConcept in a hierarchy with another, we often want to transfer all connections that went into or out of the old MathConcept to its replacement instead. This function performs that task.

This function is merely a convenient interface that just calls Connection.transferConnections() on your behalf.

Parameters

  • recipient MathConcept

    The MathConcept to which to transfer all of this one's connections

Source

unmakeIntoA(type) → {MathConcept}

For a full explanation of the typing features afforded by this function, see the documentation for isA().

This function removes the requested type to the MathConcept's attributes and returns the MathConcept itself, for use in method chaining, as in S.unmakeIntoA( 'fruit' ).setAttribute( 'sad', true ).

Admittedly, this is a pretty bad name for a function, but it is the reverse of makeIntoA(), so there you go.

Parameters

  • type string

    The type to remove from this MathConcept

Returns

  • MathConcept

    This MathConcept, after the change has been made to it

Source

unshiftChild(child)

Prepend a new child to the beginning of this MathConcept's list of children. This is equivalent to a call to insertChild() with the default second parameter (i.e., insert at index zero), and thus this function is here only for convenience, to fit with shiftChild().

Parameters

Source

untrackIDs(recursive)

This removes the ID of this MathConcept (and, if requested, all descendant MathConcepts) from the global IDs mapping. It is the reverse of trackIDs(), and should always be called once the client is finished using a MathConcept, to prevent memory leaks.

Because connections use the ID system, any connections that this MathConcept is a part of will also be severed, by a call to removeConnections().

Parameters

  • recursive boolean true

    Whether to recursively apply this function to all child, grandchild, etc. MathConcepts. (If false, only this MathConcept's ID is untracked, not those of its descendants.)

Source

Events

wasChanged

An event of this type is fired in a MathConcept immediately after one of that MathConcept's attributes is changed.

Type

  • Object

Properties

  • concept MathConcept

    The MathConcept emitting the event, which just had one of its attributes changed

  • key *

    A string value, the key of the attribute that just changed

  • oldValue *

    A JavaScript value amenable to JSON encoding, the value formerly associated with the key; this is undefined if the value is being associated with an unused key

  • newValue *

    A JavaScript value amenable to JSON encoding, the value now associated with the key; this is undefined if the key-value pair is being removed rather than changed to have a new value

See

wasInserted

An event of this type is fired in a MathConcept immediately after that MathConcept is inserted as a child within a new parent.

Type

  • Object

Properties

  • child MathConcept

    The MathConcept emitting the event, which just became a child of a new parent MathConcept

  • parent MathConcept

    The new parent the child now has

  • index number

    The index the child now has in its new parent

See

wasRemoved

This event is fired in a MathConcept immediately after that MathConcept is removed from its parent MathConcept. This could be from a simple removal, or it might be the first step in a re-parenting process that ends up with the MathConcept as the child of a new parent.

Type

  • Object

Properties

  • child MathConcept

    The MathConcept emitting the event, which was just removed from its parent MathConcept

  • parent MathConcept

    The old parent MathConcept from which the child was just removed

  • index number

    The index the child had in its parent, before the removal

See

willBeChanged

An event of this type is fired in a MathConcept immediately before one of that MathConcept's attributes is changed.

Type

  • Object

Properties

  • concept MathConcept

    The MathConcept emitting the event, which will soon have one of its attributes changed

  • key *

    A string value, the key of the attribute that is about to change

  • oldValue *

    A JavaScript value amenable to JSON encoding, the value currently associated with the key; this is undefined if the value is being associated with an unused key

  • newValue *

    A JavaScript value amenable to JSON encoding, the value about to be associated with the key; this is undefined if the key-value pair is being removed rather than changed to have a new value

See

willBeInserted

An event of this type is fired in a MathConcept immediately before that MathConcept is inserted as a child within a new parent.

Type

  • Object

Properties

  • child MathConcept

    The MathConcept emitting the event, which will soon be a child of a new parent MathConcept

  • parent MathConcept

    The new parent the child will have after insertion

  • index number

    The new index the child will have after insertion

See

willBeRemoved

This event is fired in a MathConcept immediately before that MathConcept is removed from its parent MathConcept. This could be from a simple removal, or it might be the first step in a re-parenting process that ends up with the MathConcept as the child of a new parent.

Type

  • Object

Properties

  • child MathConcept

    The MathConcept emitting the event, which is about to be removed from its parent MathConcept

  • parent MathConcept

    The current parent MathConcept

  • index number

    The index the child has in its parent, before the removal

See