The Grim formula language (draft)
Updated 2019-12-10 -- Source code on GitHub
@toc@Introduction
Grim is a symbolic language for representing mathematical formulas. Grim is human-readable, computer-readable (enabling algorithmic manipulation of symbolic expressions), and can be converted to LaTeX for rendering. Grim is being developed as a means to represent mathematics in semantic form in FunGrim: the Mathematical Functions Grimoire. A secondary goal is to have a reliable symbolic interface for Arb numerical evaluation.
Grim has two components:
- A simple core language for symbolic expressions (similar to Lisp S-expressions and Wolfram language M-expressions).
- A vocabulary of hundreds of builtin symbols for mathematical objects and operations (most of which are documented in FunGrim).
At this time, no attempt is made to provide a complete specification. Grim is defined by the reference implementation in Python (pygrim, which currently handles LaTeX conversion and some numerical evaluation via Arb), together with the 2500+ formulas added to FunGrim so far which both serve as documentation and as an informal test suite.
- Warning: Grim is currently alpha-level, and anything in this document may change. There are many known inconsistencies. Feedback is welcome on anything from mathematical foundations to syntax and naming.
Quick examples
| Grim | Generated LaTeX | Rendered formula |
|---|---|---|
| Implies(Element(n, ZZ), Equal(Sin(Mul(Pi, n)), 0)) | \left(n \in \mathbb{Z}\right) \implies \left(\sin\!\left(\pi n\right) = 0\right) | @@@Implies(Element(n, ZZ), Equal(Sin(Mul(Pi, n)), 0))@@@ |
| Equal(Exp(z), Sum(Div(Pow(z, n), Factorial(n)), For(n, 0, Infinity))) | {e}^{z} = \sum_{n=0}^{\infty} \frac{{z}^{n}}{n !} | @@@Equal(Exp(z), Sum(Div(Pow(z, n), Factorial(n)), For(n, 0, Infinity)))@@@ |
| Equal(Det(Matrix(BellNumber(Add(i, j)), For(i, 0, n), For(j, 0, n))), Product(Factorial(k), For(k, 1, n)), BarnesG(Add(n, 2))) | \operatorname{det}\displaystyle{\begin{pmatrix} B_{0 + 0} & B_{0 + 1} & \cdots & B_{0 + n} \\ B_{1 + 0} & B_{1 + 1} & \cdots & B_{1 + n} \\ \vdots & \vdots & \ddots & \vdots \\ B_{n + 0} & B_{n + 1} & \ldots & B_{n + n} \end{pmatrix}} = \prod_{k=1}^{n} k ! = G\!\left(n + 2\right) | @@@Equal(Det(Matrix(BellNumber(Add(i, j)), For(i, 0, n), For(j, 0, n))), Product(Factorial(k), For(k, 1, n)), BarnesG(Add(n, 2)))@@@ |
Goals
- Open source. Mathematics should be free!
- Easy to write. Grim is uniform, and when combined with infix arithmetic (as discussed further below), nearly as compact as LaTeX.
- Easy to parse. In fact, Grim formulas can be written within many existing programming languages (such as Python, JavaScript, Julia), relying only on the language's native syntax.
- Symbolic. Grim represents mathematics semantically. Grim expressions are meant to be easy to manipulate by symbolic computation software and precise enough to be used by theorem-proving software.
Non-goals
Grim is not designed to be a typesetting language. The details of how to display a formula are meant to be handled by the Grim-to-LaTeX converter. Nevertheless, Grim is designed to map naturally to conventional mathematical notation, and it does allow including typesetting hints in formulas where the default rendering is inadequate.
Grim is also not strict about semantic correctness! It is possible to write purely "syntactical" formulas in Grim just for the purpose of rendering via LaTeX. This is often necessary when the goal is just to display a formula (not to do symbolic computation with the expression) and a semantically correct version would be too cumbersome to express; hopefully, future improvements to the language will make such situations less common.
- TODO: semantic and non-semantic formulas could be distinguished explicitly.
Grim is not designed to be a general-purpose programming language although it can be used to encode simple functional programs performing mathematical calculations. In contrast to full-blown Lisp-like programming languages, Grim is not meant to be used to manipulate symbolic expressions "from within"; it is meant to be embedded in a host programming language where the host language can be used to traverse expression trees. Another limitation is that Grim lacks concrete data structures for programming, being mainly concerned with representing idealized and immutable mathematical objects. In general, the abstractions in Grim are designed more for expressing pure mathematics than for expressing programs.
Grim is not an automatic rewrite system. Most computer algebra systems implement rules for automatically rewriting symbolic expressions in "canonical form" (for example, converting @@x + x@@ to @@2*x@@) and must be told explicitly not to do so when rewriting is unwanted. The default assumption in Grim is that expressions are preserved verbatim. Grim expressions can be used as a basis for a rewrite system and the semantic specification is intended to serve as a guide for mathematically correct rewriting, but the specification of the Grim formula language itself does not mandate any form of automatic rewriting. Some rewriting in the presentation of a formula may take place during conversion to LaTeX, but this does not represent a change to the underlying Grim source expression.
Grim is not a good fit for all branches of mathematics. The primary goal is to express concrete results involving (complex) numbers and functions on numbers, and the builtin symbols and their semantics reflect this design. A future module/namespace system could potentially make the language more versatile.
Syntax and representation of expressions
Grim expressions
Grim has a single data structure: symbolic expression trees. A Grim expression is either of the following:
- An atom (atomic expression), being either:
- An integer literal, like 0, 1 or -42.
- A symbol, like x, Pi, Sin or Integral.
- A Unicode string, like "A grim expression: 😀".
- A non-atom (non-atomic expression), having the form f(x1, x2, ..., xn) where f, x1, x2, ..., xn are expressions. The expression f is called the head and x1, x2, ..., xn are called the arguments of the expression.
Example
An entry in FunGrim is represented by a single Grim expression that contains various metadata as well as the main formula as subexpressions. For example:
Entry(ID("22dc6e"), Formula(Equal(Fibonacci(n), Add(Fibonacci(Sub(n, 1)), Fibonacci(Sub(n, 2))))), Variables(n), Assumptions(Element(n, ZZ)))
The formula is the recurrence relation for Fibonacci numbers: @@Equal(Fibonacci(n), Add(Fibonacci(n-1), Fibonacci(n-2)))@@. The metadata in this case specifies the FunGrim entry ID (22dc6e, as a string), lists the free variables in the formula (here the single variable n), and provides conditions on the variables ("assumptions"), in this case @@Element(n, ZZ)@@, such that the formula represents a theorem.
Some points of caution
- Grim distinguishes between
the atomic expression f and the non-atomic
expression f() where f is called with an empty argument list.
- TODO: should atoms also have a head (e.g. Integer, Symbol, Text)?
- The head of an expression need not be an atom; f(g(a))(x, y) is valid.
-
Symbol names at this time are limited to ASCII Latin letters, digits and underscores,
where a digit may not appear as the first character. Since symbol names
cannot start with digits or the minus symbol, integer literals can also just
be thought of as a distinguished class of symbols.
- TODO: should probably allow Unicode
String representation and infix operators
Every Grim expression has a canonical string representation, for example Add(3, Mul(-5, x)). The simple syntax ensures that Grim expressions are syntactically valid in common programming languages. The current backend code for FunGrim (pygrim) simply embeds Grim as a domain-specific language within Python, using Python's native integer literals and function call syntax (the necessary symbols have to be created as Python variables).
The same Grim expression could be represented with different syntax where this is convenient, for example in Lisp syntax as (Add 3 (Mul -5 x)) or with infix arithmetic operators as 3 + (-5 * x). Indeed, because function-call syntax is clumsy for complex arithmetic expressions, we will frequently write Grim expressions in an extended syntactical form using infix arithmetic operators (+, -, *, /, **) as well as parentheses for grouping. In the Python implementation, operators are simply handled by overloading the Python-level arithmetic operators (with the operator precedence rules of Python). We need to be careful: for example, we can do x / 3 to construct the Grim expression Div(x, 3) in Python when x is a Grim symbol, but 1 / 3 in Python does not give Div(1, 3).
Symbols available for variables
Symbols reserved for builtin objects (such as Add and ZZ) start with an uppercase letter and are at least two characters long, so all single-letter symbols and all symbols beginning with a lowercase character can be used for variables. The Python implementation defines at least the following Python variables as Grim symbols:
@example@ Set(a, b, c, d, e, f, g, h, i, j, k, l, ell, m, n, o, p, q, r, s, t, u, v, w, x, y, z) @example@ @example@ Set(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z) @example@ @example@ Set(alpha, beta, gamma, delta, epsilon, zeta, eta, theta, iota, kappa, lamda, mu, nu, xi, pi, rho, sigma, tau, phi, chi, psi, omega) @example@ @example@ Set(Alpha, Beta, GreekGamma, Delta, Epsilon, Zeta, Eta, Theta, Iota, Kappa, Lamda, Mu, Nu, Xi, GreekPi, Rho, Sigma, Tau, Phi, Chi, Psi, Omega) @example@Most Greek letter names are available as symbols and are recognized by the LaTeX converter. There are some exceptions: Gamma is reserved for the gamma function, and Pi is reserved for the constant @@Pi@@; one should use GreekGamma and GreekPi for the Greek capital letters as variables. The alternative spelling lamda / Lamda is used for "lambda" since lambda is a reserved keyword in Python.
A convenience hack: a symbol name ending with an underscore results in function calls being rendered as subscripts (but watch out as a_ is not the same symbol as a, and the symbols are not implicitly connected):
@example@ Tuple(a_(n), gamma_(m,n), f_(n)(x)) @example@- TODO: provide a way to declare custom rendering rules for variables.
Mathematical universe
In symbolic computation, it is important to distinguish between expressions and the values they represent. The symbolic expressions @@Expr(4)@@, @@Add(2,2)@@ and @@Pow(2, 2)@@ are different as expressions, but represent the same value, the integer 4, in an imagined mathematical universe. We will often refer to values in the mathematical universe as objects. The universe of objects that can be described using Grim expressions includes the following:
- Booleans. True and False.
- Tuples. Finite ordered collections of objects.
- Sets. Possibly infinite unordered collections of objects.
- Functions. Functions, describing maps between sets.
- Numbers (and number-like objects). This comprises the integers and certain standard extensions and completions with respect to algebraic operations and limits; including rational and algebraic numbers, real and complex numbers, as well as formal polynomials and power series over numbers, and infinities.
- Matrices. Matrices are considered arithmetical objects, but distinct from scalar numbers.
- TODO: Equivalence classes / extensional sets of objects: to allow representing various arithmetic objects: residues of integers modulo @@N@@, finite field elements, algebraic number field elements, and truncated power series; in all cases viewed as equivalence classes and not as representatives in an explicit embedding.
Each item on this list denotes a family of objects belonging to a type disjoint from the other types. The notion of type is used informally here, and this list is not systematic or exhaustive.
Equality
The ordinary equality predicate Equal (@@Equal(a, b)@@) and its logical negation NotEqual (@@NotEqual(a, b)@@) are defined to compare values (objects), not to compare the expressions as syntactical trees of symbols. The same goes for the predicates for set membership, etc.
The Equal function is defined to compare objects pedantically within the mathematical universe: @@Equal(a, b)@@ if and only if @@a@@ and @@b@@ are exactly the same object. If @@Equal(a, b)@@, we will accordingly have @@Equal(f(a), f(b))@@ for any function @@f@@. Objects of different types are considered unequal even if they are in some sense isomorphic. This contract is intended to provide a solid foundation for symbolic rewriting. In contexts where this notion of equality is too strong, one should work with alternative comparison functions representing different notions of equivalence, isomorphism, etc.
- TODO: consider setoids / extensional sets.
To keep predicates and definitions involving numbers and arithmetic functions simple, all ordinary numbers belong to the same type: there is no distinction between 3 viewed as a natural number, integer, rational number, real number, or complex number. On the other hand, collection-like objects belong to different types: the 1-tuple @@Tuple(3)@@, the set @@Set(3)@@, the one-by-one matrix @@Tuple(3)@@ and the constant function @@Function(x, 3)@@ are all considered distinct objects, and distinct from the integer 3.
A subtle point is that if @@a@@ and @@b@@ both represent mathematical objects, then the value of the equality test @@Equal(a, b)@@ is considered an element of @@Set(False, True)@@ even if this equality is undecidable (or simply algorithmically hard to decide); inability to compute a value (reduce an expression to a simpler expression in the same equivalence class) is an out-of-universe concept and not an in-universe concept.
Foundations and implementations
Symbolic expressions are finite and computable as syntactical structures. One way to think of values is as equivalence classes of symbolic expressions, where @@Expr(4)@@ and @@Add(2,2)@@ belong to the same equivalence class. However, mathematical objects need not be explicitly computable. The set @@RR@@ is considered a subset (as well as an element) of the mathematical universe, but being uncountable, most of its elements cannot be represented individually by symbolic expressions. Whether the elements of @@RR@@ actually "exist" is a philosophical question, but we can manipulate the symbol @@RR@@ and expressions such as @@Set(x**2, ForElement(x, RR))@@ as if the elements exist.
The mathematical universe is not based on a particular formalized foundation of mathematics, and the Grim language does not specify how to perform concrete computations with objects (indeed, it allows expressing objects that are provably not computable!). The idea is that for actual computations, the user will implement a translation between Grim expressions and data structures and algorithms for the relevant kinds of objects. An example of this is the Arb backend for numerical evaluation, which understands a subset of Grim symbols related to real and complex numbers. The purpose of the documented Grim semantics, apart from describing the correct call syntax, is to disambiguate cases where different interpretations could be made, so that translations can be done consistently.
The universe can be extended ad-hoc by defining the meaning of previously undefined symbols and expressions. For example, a user might define the meaning of the symbol Fruits as representing a set of objects denoted by the symbols Apple and Orange and then define the meaning of operations such as @@Less(Expr(symbol_name="Apple"), Expr(symbol_name="Orange"))@@. "Define the meaning" here means providing the intended translations in an external environment using the Grim language.
Symbols, variables and expression operators
Symbols within formulas can denote specific objects (such as the constant Pi or the function Add) or variables. A symbol such as x without a builtin meaning can be used as a variable, whose meaning depends on the context. In a context where x has not been defined, any expression containing x is viewed purely as an expression which does not represent a mathematical object. We will distinguish between two kinds of variables: free variables and bound variables. (A third type of variable, an indeterminate is discussed further in the section on formal polynomials and power series. An indeterminate is not actually a variable but a distinct kind of mathematical object.)
In formulas such as @@Brackets(Where(Sin(x), Def(x, Pi/6)))@@, the function definition @@Function(x, x**2)@@, the set comprehension @@Set(x, ForElement(x, RR), Greater(x, 0))@@, the integral @@Integral(x**2, For(x, a, b))@@ or the quantified statement @@All(GreaterEqual(x**2, 0), ForElement(x, RR))@@, the symbol x is a bound variable. Binding a variable is a local operation: it overrides any meaning previously assigned to the same symbol outside the surrounding evaluation context, and the binding has no effect outside of the expression where it is used.
Some builtin symbols represent neither objects nor variables; they act as special expression operators. In an ordinary function call f(x1, x2, ..., xn), the arguments represent values (possibly unknown values represented by variables), and any argument can be replaced by any other expression representing the same value without changing the meaning. In an expression operation f(x1, x2, ..., xn), some of the arguments may need to be processed as symbolic expressions. Operators that deal with binding variables belong to this category. There is no syntactical difference between ordinary function calls and expression operations; which interpretation applies depends on the head f and whether the arguments contain special expression operators such as For, documented below. Code for manipulating expressions semantically must detect expression operators on a case by case basis.
Free variables
In a formula such as @@LessEqual(Abs(Sin(x)), 1)@@, the symbol x represents a free variable unless other context is provided. A formula containing free variables does not represent a single mathematical object but a range of possible mathematical objects; the interpretation is usually is that the formula holds when @@x@@ is replaced by any concrete value satisfying certain assumptions. In FunGrim entries, all free variables and accompanying assumptions must be declared explicitly as part of the entry metadata; in the example, Variables(x) and Assumptions(Element(x, RR)). This information can be used to interpret the formula as a quantified logical formula which no longer contains a free variable: @@All(LessEqual(Abs(Sin(x)), 1), ForElement(x, RR))@@.
Assumptions can be more complicated; for example, the content of the Assumptions() accompanying a formula with the free variables Variables(x, y) might read:
@example@ Or(And(Element(x, ZZ), Element(y, RR)), And(Element(x, RR), Element(y, CC), Or(Greater(x, 0), NotEqual(Add(x, y), 0)))) @example@Assumptions should always specify the base set of each variable unambiguously, typically by specifying @@Element(x, S)@@ where @@S@@ is a known set. It is not sufficient to state @@Greater(x, 0)@@ implying that @@x@@ should be a positive real number, because there may be other objects in the universe that satisfy this relation (for example, @@+Infinity@@).
Where/Def-expressions: local definitions
The simplest example of a locally bound variable is a symbol used as an alias for a specific value. Such aliases can be created using the Def expression operator.
@example@ Def(x, a) | Defines the meaning of the symbol x to represent the value of @@a@@ in the scope of the parent operator. @example@The Def expression has to appear as an argument to an expression operator that applies the variable binding. Currently the only such operator is Where:
@example@ Where(f(x,y), Def(x, 1/Pi), Def(y, x+1)) | The Where operator returns the value of its first argument after executing the definition statements in the subsequent arguments. The definition statements are interpreted left to right and the right-hand side values in definitions can depend on the symbols defined in the preceding definitions. @example@ @example@ Where(Equal(GCD(a, b), d, Add(Mul(a, u), Mul(b, v))), Def(Tuple(d, u, v), XGCD(a, b))) | The Where operator allows destructuring assignment (binding a tuple of variables to a tuple of values). The extended GCD function (XGCD) returns a triplet of integers. @example@Fun-expressions: constructing functions
The Fun expression operator allows constructing anonymous functions:
@example@ Fun(x, Sin(x) * Cos(x)) @example@ @example@ Fun(Tuple(x, y), Sin(x+y)*Cos(x-y)) @example@Locally named functions can be constructed by combining Where/Def with Fun:
@example@ Where(f(Pi/3), Def(f, Fun(x, Sin(x)+Cos(x)))) @example@More information is provided in the section on functions and function spaces.
For-expressions: iterations and comprehensions
The expression For(x, ...) binds the symbol x as an iteration or set comprehension variable in the parent expression, where any additional arguments ... are parameters defining the iteration. The interpretation of the parameters is up to the parent operator. Most operators recognize For() with two parameters as specifying a range of integers to iterate over:
@example@ Sum(Factorial(n), For(n, 2, 10)) | The For operator binds the variable n locally and specifies an iteration range in the scope of the parent Sum operator. @example@When For(n, a, b) is used in this sense, the endpoints @@a@@ and @@b@@ should represent integers or possibly @@Equal(a, -Infinity)@@ and/or @@Equal(b, Infinity)@@ where an infinite sequence makes sense. The iteration sequence is empty if @@Less(b, a)@@. Of course, the endpoints can be variables.
@example@ Sum(Div(1, Factorial(n)), For(n, N, Infinity)) | An infinite series. @example@Some operators may interpret the For expression differently. For example, Integral() understands two parameters as representing the endpoints (not necessarily integers) of a directed line segment to integrate over:
@example@ Equal(Integral(Cos(x), For(x, a, b)), -Integral(Cos(x), For(x, b, a))) @example@ForElement(x, S) binds the variable x just like For(x), but additionally tells the parent operator that x is to range over the elements of the set S.
@example@ Equal(Sum(1/n**2, ForElement(n, SetMinus(ZZ, Set(0)))), Pi**2/3) @example@Iteration with For and ForElement is often used in set comprehensions and as part of quantified formulas, and often together with filter predicates:
@example@ Tuple(n**2, For(n, 1, 10)) @example@ @example@ Set(f(z), ForElement(z, CC), Greater(Re(z), 0)) @example@This is discussed further below in the section on logic, sets and tuples.
Repeat-expressions and Step-expressions: variable-length argument lists
Repeat() and Step() expressions allow creating variable-length argument lists.
Repeat() generates a repeating sequence:
@example@ Repeat(1, n) @example@ @example@ Repeat(1, 2, 3, n) @example@Step() generates a sequence between two integer endpoints:
@example@ Step(Pow(k, 2), For(k, a, b)) @example@The sequence is empty if @@Less(b, a)@@, and undefined if @@a@@ and @@b@@ are not integers.
The Repeat() and Step() expressions do not represent mathematical objects; they only exist at the expression level. To construct a mathematical object, they must be used in the argument list of a function:
@example@ Tuple(Step(1/k, For(k, a, b))) @example@The Repeat() and Step() expressions generate runs of arguments that can be placed in arbitrary locations among other arguments:
@example@ f(Repeat(-1, n), 0, Step(1/k, For(k, 1, 10)), 2) @example@These expressions can be composed:
@example@ Tuple(Step(Repeat(n, n), For(n, 0, N))) @example@In this example, explicitly listing the first few items makes the pattern clearer:
@example@ Tuple(1, 2, 2, Step(Repeat(n, n), For(n, 3, N))) @example@Watch out, however: the second version is not equivalent to the first version when @@Equal(N, 0)@@ or @@Equal(N, 1)@@ since the second version always includes the leading 1, 2, 2. Visual pattern matching can be dangerous!
- TODO: Repeat() and Step() are potentially redundant; consider allowing For() directly anywhere and/or using a common Block() construct.
Logic, sets and tuples
The core mathematical abstractions in Grim deal with elementary logic and set theory.
Boolean logic
@example@ Equal(True, Not(False)) @example@ @example@ Equivalent(Not(Or(P, Q)), And(Not(P), Not(Q))) | One of De Morgan's laws. Usage note: the @@Equivalent(a, b)@@ operator does not differ semantically from the usual @@Equal(a, b)@@ operator for boolean values; it simply highlights that the equality is between booleans as opposed to an equality between some other objects. @example@ @example@ Element(RiemannHypothesis, Set(True, False)) | Boolean constants may be used to denote the truth value of unresolved mathematical conjectures, such as the Riemann hypothesis. This symbol can be used in the left-hand side of an implication or in the assumptions of a formula to denote a result conditional on the hypothesis. @example@Conditional values
The Cases operator allows choosing a value depending on the value of a logical predicate or a combination of predicates.
@example@ Equal(Sign(x), Cases(Tuple(-1, Less(x, 0)), Tuple(0, Equal(x, 0)), Tuple(1, Greater(x, 0)))) | Conditional formulas can be written using the Cases operator. @example@ @example@ Equal(Abs(x), Cases(Tuple(x, GreaterEqual(x, 0)), Tuple(0, Equal(x, 0)), Tuple(1, Or(Equal(x, 1), Equal(x, -1))), Tuple(-x, Otherwise))) | The conditions in the Cases operator can overlap, but the values for the overlapping cases should be compatible with each other so that the order of evaluation does not matter. The special Otherwise case is used when no other conditions match. If no Otherwise case is provided, the conditions should cover all possible inputs. (In this example as well as the example above, the variable @@x@@ presumably represents a real number.) @example@Logical formulas with quantifiers
Quantified logical statements can be written using the All and Exists operators, which work much like set comprehensions @@Set(P(x), ForElement(x, S), Q(x))@@ (in which @@S@@ is an arbitrary set, @@P@@ is a predicate, and @@Q@@ is an optional predicate to restrict to a subset of @@S@@). The All operator expresses the universal quantifier, while the Exists operator expresses the existence quantifier.
@example@ Equivalent(All(P(x), ForElement(x, S)), NotElement(False, Set(P(x), ForElement(x, S)))) @example@ @example@ Equivalent(All(P(x), ForElement(x, S), Q(x)), NotElement(False, Set(P(x), ForElement(x, S), Q(x)))) @example@ @example@ Equivalent(Exists(P(x), ForElement(x, S)), Element(True, Set(P(x), ForElement(x, S)))) @example@ @example@ Equivalent(Exists(P(x), ForElement(x, S), Q(x)), Element(True, Set(P(x), ForElement(x, S), Q(x)))) @example@Two concrete examples:
@example@ All(GreaterEqual(Exp(x), 1), ForElement(x, RR), GreaterEqual(x, 0)) @example@ @example@ Exists(Equal(Exp(x), 2), ForElement(x, RR), GreaterEqual(x, 0)) @example@A distinction should be made between logical formulas containing free variables and "self-contained" logical formulas such as the two examples above in which the variables are bound.
@example@ Implies(And(Element(x, RR), GreaterEqual(x, 0)), GreaterEqual(Exp(x), 1)) | This expression is incomplete as a fully quantified representation of a theorem, because x is not being declared as a bound variable; to make sense, x should be defined in the surrounding scope either as a free or bound variable. @example@ @example@ All(GreaterEqual(Exp(x), 1), ForElement(x, RR), GreaterEqual(x, 0)) | A complete quantified formula: x is a locally bound variable. @example@ @example@ All(Implies(GreaterEqual(x, 0), GreaterEqual(Exp(x), 1)), ForElement(x, RR)) | Logically equivalent to the previous example. @example@ @example@ All(Implies(And(Element(x, RR), GreaterEqual(x, 0)), GreaterEqual(Exp(x), 1)), For(x)) | Normally, the domain of the bound variable should be specified as part of the All operator, but this form is acceptable when the Implies expression contains a domain statement. @example@Printing logical formulas
Some logical operators and are rendered as text by default instead of using symbols since this tends to make the logic easier to read outside of contexts where one is working with logical formulas for their own sake. The printing style can be overridden by wrapping an expression in Logic().
@example@ All(Exists(And(Greater(x+y, 0), Not(Or(Element(x, A), Element(y, B)))), ForElement(y, T)), ForElement(x, S), Greater(x, 0)) @example@ @example@ Logic(All(Exists(And(Greater(x+y, 0), Not(Or(Element(x, A), Element(y, B)))), ForElement(y, T)), ForElement(x, S), Greater(x, 0))) @example@Constructing sets and tuples
Sets and tuples can be constructed by calling the Set and Tuple functions. The arguments can be a finite list of explicit elements, or a set comprehension or list comprehension using For / ForElement expressions.
@example@ Set(1, 2, Pi) @example@ @example@ Set() | The empty set. @example@ @example@ Set(n**2, ForElement(n, ZZ), NotEqual(n, 0)) | Set comprehension. @example@ @example@ Set(Tuple(), Tuple(1), Tuple(1,2), Tuple(1,2,Infinity)) @example@Usage note: the singleton tuple Tuple(x) (rendered as @@Tuple(x)@@) is NOT the same object as the element @@x@@.
@example@ Tuple(n, For(n, 2, 5)) @example@ @example@ Tuple(n, For(n, 1, 0)) @example@ @example@ List(1, 2, 3, 4) | Tentatively, List generates a tuple and is semantically indistinguishable from Tuple; the only difference is that List prints with square brackets. @example@ @example@ Set(n, For(n, 0, Infinity)) @example@ @example@ Set(n**2, For(n, -Infinity, Infinity)) @example@ @example@ Set(PrimeNumber(n), For(n, 1, Infinity)) @example@ @example@ Set(Pow(-1, n), ForElement(n, ZZ)) @example@ @example@ Set(f(n), For(n, -Infinity, -2)) @example@ @example@ Equal(Set(f(n), For(n, a, b)), Set(f(n), ForElement(n, ZZ), LessEqual(a, n, b))) @example@Operations on sets and tuples
@example@ Equivalent(Element(x, S), Not(NotElement(x, S))) | Set membership. @example@ @example@ Or(Subset(S, T), SubsetEqual(S, U)) @example@- TODO: should these be called ProperSubset, Subset instead?
The following sets are useful:
@example@ Sets(S) | The set of all sets with elements in @@S@@. @example@ @example@ Sets(S, n) | The set of all sets with elements in @@S@@ and having cardinality @@n@@. @example@ @example@ Tuples(S) | The set of all tuples with elements in @@S@@. @example@ @example@ Tuples(S, n) | The set of all tuples with elements in @@S@@ and having length @@n@@. @example@Abstract sets
The set @@ZZ@@ is an example of a "concrete" mathematical set; though infinite, it is meaningful to iterate over its elements. There are also "abstract" builtin sets which describe properties of objects; the actual scope of such sets is undefined. An example of an abstract set is @@Universe@@, which is simply defined to contain any object:
@example@ Universe | The universe of all objects. @example@Another example is @@Rings@@ which is the abstract set of concrete sets that are rings, such as @@ZZ@@ (discussed further in the section on algebraic structures).
Numbers and arithmetic
Grim provides various builtin functions for working with integers, rational, algebraic, real and complex numbers. Most such functions are documented in FunGrim. Here we describe some of the basic concepts.
Numbers and arithmetic
@example@ And(Equal(Add(Div(1, 3), Div(2, 3)), 1), Equal(Pow(Sqrt(2), 2), 2), NotEqual(Pow(2, 64), 0), Equal(Sin(Pi), 0)) | Grim numbers are mathematical numbers, not approximations. @example@ @example@ Equal(ConstI, Sqrt(-1), Pow(-1, Div(1, 2)), Exp(Div(1,2) * Log(-1))) | Numerical functions extend to complex numbers. Multivalued functions such as @@Sqrt(z)@@ and @@Log(z)@@ give the principal branches. (Information about branch cuts can be found in FunGrim.) Other interpretations of standard mathematical functions may be introduced as separate symbols. @example@ @example@ Add(Mul(3, a), Sub(2, 5), Div(1, 3), Pow(b, 4)) | Arithmetic operations (without using infix syntax). @example@ @example@ a*b + c/3 + x**2 + Div(1,2) - Pow(2,3) | Arithmetic operations using infix syntax in Python. (Function calls need to be used when both operands are integers, to bypass Python's arithmetic.) @example@ @example@ Equal(Neg(Neg(x)), x, Pos(x)) | Usage note: @@Pos(x)@@ represents the identity function. @example@ @example@ Tuple(Less(a, b), LessEqual(a, b), Greater(a, b), GreaterEqual(a, b), Equal(a, b), NotEqual(a, b)) | Comparisons. @example@ @example@ Equal(Decimal("-3.25"), -Div(325,100)) | Grim does not have floating-point literals or floating-point numbers as a distinct type. The Decimal function takes a decimal floating-point string as input, describing a rational number. @example@ @example@ And(Equal(Decimal("2.0e-123456789"), Div(2, Pow(10, 123456789))), Less(3, Pow(10,Pow(10,Pow(10,Pow(10,10)))))) | Reminder that we are working with symbolic expressions: numbers are not "evaluated" when constructing expressions, so we do not need to worry about large numbers causing overflow or being inefficient. @example@Infinities and undefined values
@example@ Infinity | This symbol represents a quantity larger than any real number. By definition, @@Equal(Pos(Infinity), Infinity)@@. Multiplication of @@Infinity@@ by a nonzero complex number represents an infinite limit with the given direction in the complex plane. In particular, @@Set(-Infinity, ConstI*Infinity, -(ConstI*Infinity))@@ are frequently used. @example@ @example@ UnsignedInfinity | This symbol represents a quantity with infinite magnitude and undefined sign. It is typically used to represent the value of meromorphic functions at poles, including the special case of dividing a nonzero number by zero: @@Equal(Div(1, 0), UnsignedInfinity)@@. The set @@Union(CC, Set(UnsignedInfinity))@@ represents the complex Riemann sphere. @example@ @example@ Equal(Tuple(1 / Infinity, 1 / UnsignedInfinity, Infinity + Infinity, UnsignedInfinity + UnsignedInfinity, Infinity - Infinity, Infinity / Infinity), Tuple(0, 0, Infinity, Undefined, Undefined, Undefined)) | Arithmetic involving infinities gives a number or infinity when the limiting value is unambiguous, otherwise is usually undefined. @example@ @example@ Equal(Pow(0, 0), 1) | This special case is well-defined, as a matter of convention. @example@ @example@ Equal(Infinity + 1, Infinity + ConstI, Infinity) | Any infinity completely absorbs any (finite) number added to it. This includes the case of complex numbers added to the infinities @@Set(Infinity, -Infinity)@@ with real direction. This convention will make some people unhappy some of the time, but so would the opposite convention. @example@Sets of numbers
@example@ Tuple(ZZ, QQ, RR, CC, AlgebraicNumbers) | Standard sets of numbers. @example@ @example@ And(NotElement(Sqrt(2), QQ), Element(Sqrt(2), AlgebraicNumbers), NotElement(Pi, AlgebraicNumbers), Element(Pi, RR)) @example@ @example@ Equal(QQ, Set(Div(p, q), For(Tuple(p, q)), And(Element(p, ZZ), Element(q, SetMinus(ZZ, Set(0)))))) @example@ @example@ Equal(CC, Set(Add(x, Mul(y, ConstI)), For(Tuple(x, y)), And(Element(x, RR), Element(y, RR)))) @example@ @example@ Tuple(ClosedInterval(a,b), OpenInterval(a,b), ClosedOpenInterval(a, b), OpenClosedInterval(a, b)) | Intervals represent contiguous subsets of the extended real line @@Equal(S, Union(RR, Set(-Infinity, Infinity)))@@, with or without endpoints included. The endpoints must be elements of @@S@@. @example@ @example@ Tuple(ZZGreaterEqual(1), ZZGreaterEqual(0), ZZLessEqual(0), Range(1, 10)) | Useful ranges of integers. @example@ @example@ Equal(Div(ClosedOpenInterval(4, 6), -2), OpenClosedInterval(-3, -2)) | Arithmetic operations between numbers and sets of numbers apply pointwise. @example@ @example@ Equal(Add(ClosedInterval(a, b), ClosedInterval(c, d)*ConstI), Set(x+y*ConstI, ForElement(Tuple(x, y), CartesianProduct(ClosedInterval(a, b), ClosedInterval(c, d))))) | Applying an arithmetic operation to two sets of numbers evaluates the operation over the Cartesian product of arguments. @example@ @example@ And(Subset(AlgebraicNumbers, CC), Element(Sqrt(-1), AlgebraicNumbers), Element(Sqrt(-1), CC)) | The algebraic numbers are considered canonically embedded in the complex numbers. @example@p-adic numbers
The p-adic numbers (for a given prime @@p@@) are an extension of the rational numbers.
@example@ And(Subset(ZZ, ZZp(p)), Subset(QQ, QQp(p)), Subset(ZZp(p), QQp(p))) @example@The p-adic number 1 is considered the same object as the integer 1 and the complex number 1, and rational arithmetic involving p-adic numbers requires no special notation. However, mixing p-adic numbers with irrational real and complex numbers is meaningless. Any operation that implicitly or explicitly involves norms or limits (such as summation of infinite series and evaluation of transcendental functions) must be expressed using dedicated functions for the p-adic norm.
- TODO: This is tentative...
- TODO: Algebraic numbers with p-adic numbers.
Functions
The term function, just like variable, is ambiguous. We will distinguish between (proper) univariate functions, (proper) multivariate functions, and improper functions.
A univariate function or simply function is an object @@f@@ with an associated set @@S@@ called the domain of @@f@@ such that @@f(x)@@ represents a unique value for any @@Element(x, S)@@.
A multivariate function is an object @@f@@ with an associated set @@S@@ of tuples called the (multivariate) domain of @@f@@ such that @@f(Subscript(x,k), For(k,1,n))@@ represents represents a unique value for any @@Element(Tuple(Subscript(x,k), For(k,1,n)), S)@@.
A univariate function is the same thing as a multivariate function on a set of 1-tuples. Note that a multivariate function defined on 2-tuples is not the same thing as a univariate function defined on 2-tuples: we distinguish between @@f(x,y)@@ and @@f(Tuple(x,y))@@. The latter is the same thing as a multivariate function defined on 1-tuples of 2-tuples.
An improper function is an object that can be called as a (multivariate) function but does not have a delimited domain. Most builtin symbols in Grim actually denote improper functions. For example, the symbols Add and Exp represent improper functions which are defined not only on the real and complex numbers @@RR@@ and @@CC@@ but also for infinities, formal power series and many other kinds of objects.
We will generally use function to mean improper function except in contexts where we discuss function spaces as sets. When disambiguation is necessary, univariate or multivariate functions in the ordinary mathematical sense (with delimited domains) will be called proper functions. An improper function can be converted to a proper function (such as the real exponential function @@Equal(f(x), Exp(x))@@ with domain @@Element(x, RR)@@) by restricting it to a concrete domain.
Defining improper functions
Improper functions can be defined using the Fun expression operator.
@example@ Fun(x, x**2) | Defines a univariate improper function mapping the symbol given as the first argument to the expression in the second argument. The symbol x representing the dummy variable becomes locally bound within the context of the arguments of the Fun operator. @example@ @example@ Fun(Tuple(x, y), 2*x+3*y) | Defines a bivariate function. The symbols x and y become locally bound. @example@ @example@ Fun(Tuple(x), x**2) | Equivalent to defining a univariate function. @example@ @example@ Fun(Tuple(x_(i), For(i, 1, n)), Sum(i * x_(i), For(i, 1, n))) | Defines a multivariate function with arity @@n@@. In this special case, the variable binding x_ in the scope of the Tuple call propagates through to the Fun operator. @example@ @example@ Equal(Fun(x, x**2)(3), 9) | Calling a function. @example@ @example@ Equal(Fun(x, Sin(x)/x)(0), Undefined) | Function evaluation is equivalent to naively applying the operations in the defining expression tree to the value. It is not implied to compute limits where the result would be undefined. @example@ @example@ Equal(Fun(x, Cases(Tuple(Sin(x)/x, NotEqual(x, 0)), Tuple(1, Equal(x, 0))))(0), 1) | Here we define the sinc function with the correct limiting value at the origin. @example@Defining named improper functions
@example@ Where(g(c_(2), c_(3)), Def(c_, Fun(n, n**2+n+1)), Def(g, Fun(Tuple(x, y), (x+y)*(x-y)))) | Defining and calling named improper functions in the context of a Where expression. @example@Proper functions and domains
@example@ Restriction(f, S) | The function @@f@@ restricted to the domain @@S@@, creating a proper univariate function. @example@ @example@ MultivariateRestriction(g, T) | The function @@g@@ restricted to the multivariate domain (set of tuples) @@T@@, creating a proper multivariate function. @example@ @example@ Restriction(Fun(n, Factorial(n)), ZZGreaterEqual(0)) | Defining a proper function, in this case with the nonnegative integers as the domain. @example@ @example@ MultivariateRestriction(Fun(Tuple(x, y), x / y), CartesianProduct(RR, SetMinus(RR, Set(0)))) | Defining a proper bivariate function: the division operator on the real numbers, excluding zero in the denominator. @example@Function spaces
@example@ Functions(S, T) | The set of all (proper) functions from @@S@@ to the set @@T@@. @example@ @example@ MultivariateFunctions(S, T) | The set of all (proper) multivariate functions from the set of tuples @@S@@ to the set @@T@@. @example@ @example@ Where(Element(MultivariateRestriction(Fun(Tuple(x, y), x / y), S), Parentheses(MultivariateFunctions(S, QQ))), Def(S, CartesianProduct(ZZ, SetMinus(ZZ, Set(0))))) | Division maps integers, restricted to exclude zero denominators, to rational numbers. @example@ @example@ Element(MultivariateRestriction(Brackets(Fun(Tuple(x, y), x / y)), CartesianPower(ZZ, 2)), Parentheses(MultivariateFunctions(CartesianPower(ZZ, 2), Union(QQ, Set(UnsignedInfinity, Undefined))))) | Division as a total function for pairs of integers (@@Equal(Div(1, 0), UnsignedInfinity)@@ and @@Equal(Div(0, 0), Undefined)@@). @example@ @example@ Element(Restriction(Sin, RR), Parentheses(Functions(RR, ClosedInterval(-1, 1)))) | The symbol @@Sin@@ represents a function defined for many different types of objects. The restriction belongs to the space of functions defined on @@RR@@, and even more narrowly to the space of functions from @@RR@@ to @@ClosedInterval(-1,1)@@. @example@ @example@ Set(f, ForElement(f, Functions(CC, CC)), IsHolomorphic(f(z), ForElement(z, CC))) | This constructs the space of holomorphic functions on the complex plane. @example@Undefined values
@example@ Undefined | A distinguished object used to represent the result of evaluating functions outside of their domain of definition. (This includes both proper functions and improper functions outside the domain where they are implicitly meaningful.) @example@ @example@ Equal(Add(True, Pi), Undefined) | Example: addition is not defined for booleans. @example@Sequences and multidimensional arrays
Sequences and multidimensional arrays do not have a designated "type" in Grim, but can defined naturally as functions.
Sequences can be defined as functions with a subset of @@ZZ@@ as the domain, typically @@ZZGreaterEqual(a)@@ for an infinite sequence with the initial term at offset @@a@@. A doubly infinite sequence can be thought of as a function on @@ZZ@@.
Similarly, n-dimensional arrays are conveniently described as functions from a subset of @@CartesianPower(ZZ, n)@@ to the value set. For example, a function @@a(i,j,k)@@ (alternatively, using subscript notation @@a_(i,j,k)@@) in @@Functions(CartesianProduct(Range(0,M), Range(1,N), Range(1,P)), CC)@@ denotes a three-dimensional complex array of size @@(M+1) * N * P@@ where the first dimension is indexed from zero and the remaining indices are indexed from one.
- TODO: syntax for defining array-like functions from the list of values.
Tuples constructed using Tuple() are however considered a distinct type of object from functions defined on @@Range(1,n)@@, and similarly for matrices constructed using Matrix().
Calculus: summation, solving, and other operations
Grim provides a wide range of builtin operators for operations on functions, allowing the symbolic representation of integrals, derivatives, sums, products, limits, extreme values and solution sets. The Operators page in FunGrim lists such operators and gives detailed explanations of the syntax (under the "Details" view for each entry). We give some quick examples below.
In general, the following operators represent the input function in terms of an expression along with a For-expression for the bound variable (or variables): for example, Sum(f(n), For(n, 0, Infinity)).
- TODO: an alternative would be to omit the dummy variable and pass a function object as input, e.g. Sum(f, 0, Infinity).
Sums and integrals
@example@ Sum(f(n), For(n, -Infinity, Infinity)) @example@ @example@ Product(f(n), For(n, 1, Infinity)) @example@ @example@ Sum(f(n), ForElement(n, ZZ)) @example@ @example@ Sum(f(n), ForElement(n, ZZ), NotEqual(n, 0)) @example@ @example@ Integral(f(x), For(x, -Infinity, Infinity)) @example@ @example@ Integral(f(x), ForElement(x, S)) @example@Special operators are provided for sums and products over divisors and primes:
@example@ Equal(RiemannZeta(s), PrimeProduct(1/(1-p**(-s)), For(p))) @example@ @example@ Equal(DivisorSum(Totient(d), For(d, n)), n) @example@ @example@ Element(Parentheses(BernoulliB(2*n) + PrimeSum(1/p, For(p), Divides(Parentheses(p-1), 2*n))), ZZ) @example@Solutions and zeros
@example@ Equal(Pi, UniqueZero(Sin(x), ForElement(x, ClosedInterval(3, 4)))) @example@ @example@ Equal(Zeros(a*z**2+b*z+c, ForElement(z, CC)), Set((-b+Sqrt(b**2-4*a*c))/(2*a), (-b-Sqrt(b**2-4*a*c))/(2*a))) @example@ @example@ Equal(Solutions(Brackets(Equal(Mul(w, Exp(w)), z)), ForElement(w, CC)), Set(LambertW(k, z), For(k), And(Element(k, ZZ), Or(NotEqual(z, 0), Equal(k, 0))))) @example@ @example@ All(Equal(UniqueSolution(Brackets(Equal(Mul(w, Exp(w)), x)), ForElement(w, ClosedOpenInterval(-1, Infinity))), LambertW(0, x)), ForElement(x, ClosedOpenInterval(Neg(Div(1, ConstE)), Infinity))) @example@Limits
Whether a limit is well-defined can depend on the set of approach. For example, @@Limit(Sin(Pi*n), For(n, Infinity))@@ exists as a sequence limit (@@n@@ restricted to integers) but not as a real limit (@@n@@ allowed to be real). In mathematical notation the set of approach is usually only implied, but Grim allows specifying the set explicitly with a predicate.
@example@ Equal(Limit(Sin(Pi*n), For(n, Infinity), Element(n, ZZ)), 0) @example@ @example@ Equal(Limit(Sin(Pi*x), For(x, Infinity), Element(x, RR)), Undefined) @example@Alternatively one of SequenceLimit, RealLimit, ComplexLimit can be used; this omits rendering the set of approach in the LaTeX formula but the precise semantics can still be inferred from the source Grim expression:
@example@ Equal(RealLimit(Sinc(x), For(x, Infinity)), 0) @example@ @example@ Equal(ConstGamma, SequenceLimit(Brackets(Sub(Parentheses(Sum(Div(1, k), For(k, 1, n))), Log(n))), For(n, Infinity))) @example@ @example@ Equal(ConstGamma, -ComplexLimit(Brackets(Gamma(z) - Div(1, z)), For(z, 0))) @example@Directional limits can be expressed:
@example@ Equal(RightLimit(f(x), For(x, 0)), Limit(f(x), For(x, 0), Element(x, OpenInterval(0, 1)))) @example@ @example@ Equal(ConstGamma, RightLimit(Brackets(Sub(Mul(Div(Pi, 2), BesselY(0, x)), Log(Div(x, 2)))), For(x, 0))) @example@Other limit-type operators exist, for example:
@example@ Equal(SequenceLimitInferior(Div(Mul(Totient(n), Log(Log(n))), n), For(n, Infinity)), Exp(-ConstGamma)) @example@Extrema
@example@ Equal(Maximum(Brackets(Sin(x)), ForElement(x, RR)), 1) @example@ @example@ Equal(ArgMin(Brackets(Sin(x)), ForElement(x, RR)), Set(Mul(Pi, Sub(Mul(2, n), Div(1, 2))), ForElement(n, ZZ))) @example@ @example@ Equal(ArgMinUnique(Brackets(Cosh(x)), ForElement(x, RR)), 0) @example@Derivatives
Derivative() takes one or two parameters, denoting the evaluation point and optionally the order of differentiation:
@example@ Tuple(Derivative(f(x), For(x, y)), Derivative(f(x), For(x, y, 2)), Derivative(f(x), For(x, y, n))) @example@The compact LaTeX rendering above (with primes, omitting the bound variable) is used when the input expression is a simple function call. In general, derivatives are rendered in a more verbose way:
@example@ Tuple(Derivative(Parentheses(f(x)+g(x)), For(x, y)), Derivative(Parentheses(f(x)+g(x)), For(x, y, 2)), Derivative(Parentheses(f(x)+g(x)), For(x, y, n))) @example@As with Limit, the notion of derivative is ambiguous and one should use RealDerivative, ComplexDerivative (etc.) depending on the situation.
Analytic continuation
@example@ Equal(AnalyticContinuation(Log(R*Exp(ConstI*t)), For(t, 0, theta)), Log(R) + theta*ConstI) @example@Matrices and linear algebra
The interface for matrices is being developed.
@example@ Equal(Det(Matrix2x2(a, b, c, d)), a*d-b*c) @example@ @example@ Matrix(a_(i,j), For(i, 1, M), For(j, 1, N)) @example@ @example@ Matrices(R, m, n) | The set of @@m@@ by @@n@@ matrices with elements in @@R@@. @example@- TODO: block matrices/flattening. Element access. Relation between matrices, vectors, lists/tuples. Additional matrix operations; vector spaces.
Algebraic structures
An algebraic structure is a set of objects together with a collection of operations on that set required to satisfy certain properties. Groups, rings, and fields are common examples. The most important algebraic structures are rings of numbers, matrices, polynomials, power series, and residue classes.
There are potentially two ways to formalize the definition of an algebraic structure: the first approach is to identify the algebraic structure with the set of objects, understanding that the arithmetic functions Add, Mul, etc. implement the operations. The second approach is to identify the algebraic structure with a tuple @@Tuple(S, f, g, Ellipsis)@@ where @@S@@ is the set of objects and @@f@@ and @@g@@ (etc.) are functions for the relevant operations. Grim favors the first approach, as it makes it easier to write formulas that are valid for generic objects.
@example@ Implies(And(Element(R, CommutativeRings), Elements(x, y, R)), Equal((x+y)**2, x**2+2*x*y+y**2)) @example@Rings and fields
Any set of objects whose elements satisfy the usual ring axioms (with respect to the normal arithmetic operators Add, Mul, etc.) is considered an element of @@Rings@@, and similarly for other kinds of algebraic structures:
@example@ Element(Matrices(ZZ, 2, 2), Rings) | An example of a ring. @example@ @example@ Element(ZZ, CommutativeRings) | An example of a commutative ring. @example@ @example@ Element(QQ, Fields) | An example of a field. @example@Rings may consist of other types of objects than numbers. In particular, the identity elements of a ring need not be the same objects as the numbers (integers) 0 and 1.
@example@ Zero(R) | The zero element (additive identity) of the ring @@R@@. @example@ @example@ One(R) | The unit element (multiplicative identity) of the ring @@R@@. @example@ @example@ Equal(One(Matrices(CC, 2, 2)), Matrix2x2(1, 0, 0, 1)) | A ring where the unit element is not the same object as the number 1. @example@ @example@ Characteristic(R) | The characteristic of the ring @@R@@. @example@In rings that do not contain the integers as a subset, ring elements can still mix with ordinary integers in arithmetic operations, and then "absorb" the integers (that is, the unique ring homomorphism @@Functions(ZZ, R)@@ applies automatically). If @@And(Element(R, Rings), Element(r, R))@@, we have for example:
@example@ Equal(0 * r, r - r, Zero(R)) | However, @@Equal(0 * r, r - r, 0)@@ does not hold if the zero element is not the number 0: equality in the sense of the Equal operator is a more fundamental operation than arithmetic, and is not interpreted in the sense of a homomorphism.@example@ @example@ And(Equal(r + 0, r), Equal(1 * r, r), Equal(Zero(R) + 1, One(R)), Equal(2 * r, r + r), Equal(r**0, One(R))) @example@Caution: operators such as Sum and Product work over generic rings, but they are understood to return the integers 0 and 1 when applied to the empty set of terms. To write semantically correct formulas that work over generic rings, one should handle the empty case separately or add the identity explicitly as a "coercion":
@example@ Zero(R) + Sum(A(n), For(n, 1, N)) | Works when @@Equal(N, 0)@@. @example@Extension rings and fields
A ring or field can be extended by adjoining generating elements:
@example@ Element(Sqrt(2)+5*Sqrt(3), Polynomials(ZZ, Sqrt(2), Sqrt(3))) | An element in a ring of algebraic numbers. @example@ @example@ Element(1/(Sqrt(2)+Sqrt(3)), PolynomialFractions(QQ, Sqrt(2), Sqrt(3))) | The corresponding fraction field. @example@ @example@ Element((Pi+1)/(Pi-1), PolynomialFractions(QQ, Pi)) | An element in a transcendental number field. @example@ @example@ Element(Sum(Sqrt(n), For(n, -10, 10)), PolynomialFractions(QQ, Set(Sqrt(n), ForElement(n, ZZ)))) | The smallest field containing all square roots of integers. @example@In general, @@Polynomials(R, S)@@ denotes the ring generated by polynomials in elements of @@R@@ and @@Set(S)@@ (or @@S@@ if this is already a set). The elements of this ring should be understood as converted to a common type (in principle, by adding the zero element of all constituent rings to each element): for example, @@Polynomials(Matrices(QQ, 2, 2), Sqrt(2))@@, does not contain the numbers 0, 1 or @@Sqrt(2)@@ as objects; the corresponding scalar elements of this ring are the scalar matrices @@Matrix2x2(c,0,0,c)@@.
Residue rings
Unlike extension rings which can be formed by adding new elements to an existing set, residue rings require forming new types of objects. For example, the ring of integers mod 2 has to be represented by a new set of objects @@Set(Subscript(0, 2), Subscript(1, 2))@@ if we want to use the usual arithmetic operations Add etc., since the usual integers @@Subset(Set(0, 1), ZZ)@@ have a different arithmetic. This means that elements of a residue ring cannot compare as equal to the elements in the larger ring; one has to apply a homomorphism explicitly to compare elements between the rings.
- TODO: residue rings, finite fields
Formal polynomials and power series
To represent polynomials and polynomial-like objects in the algebraic sense (rather than as functions or expressions), one can adjoin indeterminates to numbers. The following sets of indeterminates are built-in:
- Standard polynomial indeterminates (XX): @@Equal(XX, Set(XX(1), XX(2), Ellipsis))@@
- Standard series indeterminates (XXSeries): @@Equal(XXSeries, Set(XXSeries(1), XXSeries(2), Ellipsis))@@
- Standard noncommutative polynomial indeterminates (XXNonCommutative): @@Equal(XXNonCommutative, Set(XXNonCommutative(1), XXNonCommutative(2), Ellipsis))@@
Each set contains infinitely many indeterminates. Calling the set with an index @@n@@ as the argument returns the @@n@@-th indeterminate:
@example@ Subset(Set(XX(1), XX(2), XX(4)), XX) | Standard indeterminates for constructing polynomials. @example@Indeterminates can be assigned to ordinary variables, just like any other objects:
@example@ Where(Equal((x+Sqrt(2))*(x-Sqrt(2)), x**2-2), Def(x, XX(1))) @example@Indeterminates are not the same thing as free variables; they are particular objects in the mathematical universe that generate algebraic structures such as the polynomial ring @@Polynomials(CC, XX(1), XX(2))@@. The index does not necessarily need to be an integer: an object such as a tuple could also be used to label a unique indeterminate, e.g.: @@XX(Tuple(3,4))@@. Even more simply, XX() gives an indeterminate rendered as @@XX()@@, useful in contexts where only a single variable needs to be considered.
Indeterminates should not be confused with symbols or variables. For example, the expression Fun(XX(), XX()**2+1) is meaningless because XX() has a reserved meaning and cannot be used as the name of an expression-level variable. (Evaluating a polynomial constructed from an indeterminate uses a different syntax.) Further, two variables can refer to the same object, including the same indeterminate: one can have @@Equal(x, y, XX(1))@@, but one always has @@NotEqual(XX(1), XX(2))@@. More generally, an indeterminate is distinct from any number and from any other indeterminate: for example, we have @@NotEqual(x, 0)@@ by definition when @@x@@ is any indeterminate, while the truth of @@Equal(x, 0)@@ is unknown if @@x@@ is a free variable (unless that variable is constrained to exclude zero through assumptions).
Indeterminates and variables
Typically, one wants to assign an indeterminate to an ordinary variable when writing down a formula:
@example@ Where(Equal((x+y)**2, x**2+2*x*y+y**2), Def(x, XX(1)), Def(y, XX(2))) | In this Where expression, the expression-level variables @@x@@ and @@y@@ are defined as aliases for the standard polynomial indeterminates @@XX(1)@@ and @@XX(2)@@. @example@The index of the indeterminate is often unimportant. An alternative way to write a formula involving an indeterminate is to leave the expression-level variables (such as x) as free variables and state that the formula holds for any choice of indeterminate:
@example@ Implies(Elements(x, y, XX), Equal((x+y)**2, x**2+2*x*y+y**2)) @example@Note that in the above example, x and y could actually refer to the same indeterminate. This can be avoided as follows:
@example@ Implies(DistinctElements(x, y, XX), Equal((x+y)**2, x**2+2*x*y+y**2)) @example@Referencing the same indeterminate with different variables can also be deliberate:
@example@ Where(Equal(x**2*y, x*y*z), Def(x, XX(1)), Def(y, XX(2)), Def(z, x)) | Here both @@x@@ and @@z@@ are set to @@XX(1)@@. @example@A much more elaborate example of a formula, involving a variable number of indeterminates:
@example@ Where( Equal( Sum(x_(i), For(i, 1, m))**n, Sum((Factorial(n) / Product(Factorial(Item(k, i)), For(i, 1, m)) * Product(x_(i)**Item(k, i), For(i, 1, m))), ForElement(k, S))), Def(x_, Fun(k, XX(k))), Def(S, Set(k, ForElement(k, CartesianPower(Range(0,n), m)), Equal(Sum(Item(k, i), For(i, 1, m)), n)))) | The multinomial theorem for the standard polynomial indeterminates. @example@Rings and fields of polynomials
Standard indeterminates are named as such because they have familiar algebraic properties: for example, any standard indeterminate @@x@@ satisfies @@Equal(Sub(x, x), 0)@@, @@NotEqual(x**n, 0)@@ for all @@Element(n, ZZ)@@, and @@Equal(x**0, x * x**-1, 1)@@. (In nonstandard circumstances, one might want different properties: for example, @@Equal(x**2, 0)@@ would allow representing dual numbers.) More precisely, the standard polynomial indeterminates generate a universal ring @@Equal(Polynomials(CC, XX), Polynomials(CC, XX(1), XX(2), Ellipsis))@@ of formal multivariate polynomials with the usual properties of commutative algebra. If @@R@@ is a subring of @@CC@@ (for example, @@ZZ@@, @@QQ@@ or @@CC@@), we have:
@example@ Subset(Polynomials(R, XX(1)), Polynomials(R, XX(1), XX(2), XX(3)), Polynomials(R, XX)) | Formal polynomials in one variable, a few variables, and in any finite combination of variables. @example@By extension, quotients involving such polynomials (for example: @@Element(1/(XX(1)-1), PolynomialFractions(QQ, XX(1)))@@) generate a universal field of formal polynomial fractions:
@example@ Subset(PolynomialFractions(R, XX(1)), PolynomialFractions(R, XX(1), XX(2), XX(3)), PolynomialFractions(R, XX)) | Formal polynomial fractions in one variable, a few variables, and in any finite combination of variables.@example@By formal polynomial, we mean a particular kind of algebraic object. Formal polynomials are different from expressions: @@(XX(1)+1)*(XX(1)-1)@@ and @@XX(1)**2-1@@ describe the same quadratic polynomial just like @@(Pi+1)*(Pi-1)@@ and @@Pi**2-1@@ describe the same real number; viewed from within the mathematical universe, this object has no "memory" of which expression was used to construct it. The formal polynomial @@XX(1)**2-1@@ is also not the same thing as the polynomial function @@Fun(x, x**2-1)@@: it is an entirely different type of object. A more common name for polynomial fraction is rational function, but we avoid this term in the algebraic context to avoid confusion with rational functions as functions.
The objects generated by compatible standard indeterminates are considered to belong to a large shared set in which subrings are simply subsets: just as @@Subset(ZZ, QQ, RR, CC)@@, we have @@Subset(ZZ, CC, Polynomials(CC, XX(1)), PolynomialFractions(CC, XX(1), XX(2)))@@, and @@Subset(Polynomials(Polynomials(QQ, XX(2)), XX(1)), Polynomials(CC, XX(1), XX(2), XX(3)))@@. This construction is not flexible enough for all applications: just to mention two limitations, @@Polynomials(CC, XX(1), XX(2))@@ and @@Polynomials(Polynomials(CC, XX(1)), XX(2))@@ are exactly the same ring (some applications require making a distinction), and the identity elements @@Equal(XX(1)**0, 1)@@ and @@Equal(0*XX(1), 0)@@ are the usual integers (potentially inconvenient for working with polynomials over non-number base rings).
Noncommutative polynomials
Noncommutative indeterminates are compatible with the commutative indeterminates:
@example@ Implies(And(Elements(a, b, XX), DistinctElements(A, B, XXNonCommutative)), And(NotEqual(A*B, B*A), Equal(b*A*a*B**2*2*B**(-1), 2*a*b*A*B))) | Noncommutative indeterminates do not commute with each other, but commute with commutative indeterminates and with complex numbers. @example@ @example@ Element((XX(1)+Sqrt(2))/((2+3*ConstI)*XX(2)+1) * XXNonCommutative(1)**2 * XXNonCommutative(2), Polynomials(PolynomialFractions(CC, XX), XXNonCommutative)) | A universal ring of noncommutative polynomials with complex polynomial fractions as coefficients. @example@Noncommutative indeterminates may be used, for example, to model @@n@@ by @@n@@ matrices for an unspecified @@n@@, under the assumption that matrices satisfy no commutation relations. However, one should be careful since @@0*XXNonCommutative(1)@@ and @@XXNonCommutative(1)**0@@ are defined to represent the integers 0 and 1 rather than the zero and identity matrices for some @@n@@.
@example@ Element((1+2*ConstI)*XXNonCommutative(1) * Matrix2x2(1, XX(1)+1, -XX(3)**-2, 1) * XXNonCommutative(1)**2 * XXNonCommutative(2), Polynomials(Matrices(PolynomialFractions(CC, XX), 2, 2), XXNonCommutative)) | Mixing noncommutative indeterminates with two by two matrices with polynomial fraction elements. Note: in order for the set on the right to be interpreted as a ring, it must be understood to exclude scalar numbers so that there is a unique identity element; the 2-by-2 identity matrix. @example@Evaluation and composition
A special function is used to replace indeterminates (or combinations of indeterminates) by given values which can be numbers, indeterminates, or other objects:
@example@ Equal(EvaluateIndeterminate(XX(1)**2 + XX(2), XX(1), 2), 4 + XX(2)) @example@ @example@ Equal(EvaluateIndeterminate(XX(1)**2 + XX(2), Tuple(XX(1), XX(2)), Tuple(2, 1)), 5) @example@ @example@ Equal(EvaluateIndeterminate(XX(1)**2 + XX(2), Tuple(XX(1), XX(2)), Tuple(XX(2)+1, XX(1))), (XX(2)+1)**2 + XX(1)) @example@Since the representation (monomial basis, factored, etc.) of a polynomial is undefined, it is assumed that the evaluation point is an object such that the evaluation map is unambiguous.
To define polynomial functions, one can evaluate an indeterminate at the value given by the bound variable in a Fun-expression:
@example@ Fun(x, EvaluateIndeterminate(XX(1)**2 + 1, XX(1), x)) @example@As a special case, polynomial fractions expressed in terms of standard polynomial indeterminates can be assumed to correspond to reduced forms without removable singularities: the function @@Fun(x, (x-2) / (x-2))@@ is undefined (@@Div(0, 0)@@) when evaluated at 2, but the formal polynomial fraction @@(XX(1)-2) / (XX(1)-2)@@ represents the constant integer 1, and equals 1 when evaluated at @@Equal(XX(1), 2)@@.
The function CallIndeterminate can be used instead of EvaluateIndeterminate when the variable or variables are clear from the context; it has exactly the same semantics as EvaluateIndeterminate but prints as an ordinary function call without displaying the indeterminate:
@example@ Equal(AlgebraicNumbers, Set(z, ForElement(z, CC), Parentheses(Exists(Equal(CallIndeterminate(f, XX(), z), 0), ForElement(f, SetMinus(Polynomials(ZZ, XX()), Set(0))))))) @example@Power series
The standard series indeterminates @@Equal(XXSeries, Set(XXSeries(n), For(n, 1, Infinity)))@@ have the property that powers of the indeterminates converge in the topology of formal power series: @@Equal(Limit(c_(n) * XXSeries(1)**n, For(n, Infinity)), 0)@@ for any sequence of complex numbers @@c_(n)@@. The Sum and Product operators recognize this notion of convergence, so that formal power series can be expressed in a natural way as infinite series and products involving series indeterminates.
@example@ Where(Sum(Factorial(n) * x**n, For(n, 0, Infinity)), Def(x, XXSeries(1))) | This is a valid formal power series (with radius of convergence 0). @example@Series indeterminates behave like polynomial indeterminates with respect to addition and multiplication, but differ in other respects: polynomial indeterminates are essentially inert outside of ring and field operations, while series indeterminates generate formal series expansions.
An important difference is that quotients of polynomial indeterminates create formal polynomial fractions while quotients of series indeterminates create the formal power series (or more generally Laurent series) expansions of rational functions at 0. The distinction matters for evaluation: the formal polynomial fraction @@1/(1-XX(1))@@ can be evaluated anywhere on the complex plane (representing a meromorphic function), but the corresponding formal power series @@1+XXSeries(1)+XXSeries(1)**2+Ellipsis@@ needs to be analytically continued outside of the unit disk. The distinction also matters for arithmetic in several variables since multivariate polynomial fractions are well-defined arithmetically but have non-unique multivariate Laurent expansions.
Likewise, @@Exp(XX(1))@@ represents a term that is algebraically independent of @@XX(1)@@ (allowing one to express formal exponential polynomials such as @@XX(1)*Exp(XX(1)) + 5*XX(1)*Exp(2*XX(1))@@), while @@Exp(XXSeries(1))@@ gives the formal power series @@1 + XXSeries(1) + XXSeries(1)**2/2 + Ellipsis@@.
@example@ Implies(Elements(x, y, XXSeries), Equal(Exp(x+y), Exp(x)*Exp(y), Sum((x+y)**n/Factorial(n), For(n, 0, Infinity)), Parentheses(Sum(x**n/Factorial(n), For(n, 0, Infinity))) * Parentheses(Sum(y**n/Factorial(n), For(n, 0, Infinity))))) @example@We can construct rings of formal power series and Laurent series:
@example@ Subset(PowerSeries(R, XXSeries(1)), PowerSeries(R, XXSeries(1), XXSeries(2), XXSeries(3)), PowerSeries(R, XXSeries)) | Formal power series in one variable, a few variables, and in any finite combination of variables. @example@ @example@ Subset(LaurentSeries(R, XXSeries(1)), LaurentSeries(R, XXSeries(1), XXSeries(2), XXSeries(3)), LaurentSeries(R, XXSeries)) | Formal Laurent series in one variable, a few variables, and in any finite combination of variables. @example@More generally, the standard series indeterminates are compatible with the standard polynomial indeterminates, and when combined allow expressing formal power series with polynomials (or polynomial fractions) as coefficients:
@example@ Where(Element(Sum((Parentheses(Product(Parentheses(a+k), For(k, 1, n))) / Parentheses(Product(Parentheses(b+k), For(k, 1, n)))) * (x**n / Factorial(n)), For(n, 0, Infinity)), PowerSeries(PolynomialFractions(CC, a, b), x)), Def(a, XX(1)), Def(b, XX(2)), Def(x, XXSeries(1))) @example@Note that the example above represents a definite object in the mathematical universe, not containing any free variables. If we use evaluated complex-valued functions instead of formal polynomial fractions, we express a formal power series with ordinary (but possibly unknown) complex coefficients. In the following example, the coefficients are unknown complex numbers if @@f@@ and @@g@@ are interpreted as free variables:
@example@ Where(Implies(And(Element(f, Functions(ZZ, CC)), Element(g, Functions(ZZ, SetMinus(CC, Set(0))))), Element(Sum((f(n) / g(n)) * (x**n / Factorial(n)), For(n, 0, Infinity)), PowerSeries(CC, x))), Def(x, XXSeries(1))) @example@- TODO: There are subtle problems with defining power series and Laurent series in several variables; this needs elaboration.
- TODO: Puiseux series. Generalized series expansions?
Non-semantic markup
The Grim to LaTeX converter is intended to produce beautifully rendered, natural-looking formulas from expressions written in a semantically natural way. Nevertheless, the results are not always perfect, and sometimes manual rendering hints are needed.
Decorations and display style
The following functions semantically represent the identity function, but provide hints to the LaTeX converter:
@example@ AngleBrackets(Parentheses(x + Brackets(a - b)) * Braces(s - t)) | Parentheses, Brackets, Braces and AngleBrackets hint that the enclosed expression should be surrounded by ( ), [ ], { } and ⟨ ⟩ respectively. @example@ @example@ Equivalent(Equivalent(Not(Or(P, Q)), And(Not(P), Not(Q))), Logic(Equivalent(Not(Or(P, Q)), And(Not(P), Not(Q))))) | The Logic function hints that logical operators in the enclosed expression should be rendered using symbols instead of text. @example@ @example@ Equal(Tuple(1/(i+1)**2, For(i, 0, 9)), Tuple(Evaluated(1/(i+1)**2), For(i, 0, 9))) | The Evaluated function hints that the converter should apply symbolic simplifications (such as constant folding of rational numbers) to the enclosed expression before display. The precise simplification rules to be used are at the discretion of the converter (this should perhaps be configurable by the user). @example@- TODO: other hints: small/large display style? Patterns vs comprehension? Some of these should be options to the renderer rather than part of the formula language.
Gibberish
It is sometimes useful to write Grim expressions which are syntactically valid but semantically incorrect (or at least semantically under-specified), just for rendering formulas for a human reader. Here are some typical examples:
@example@ Equal(Set(n**2, For(n, 1, Infinity)), Set(1, 4, 9, 16, Ellipsis)) | The Ellipsis symbol does not have a formal interpretation; the right-hand side (and hence the equation as a whole) is semantically meaningless. @example@ @example@ Equal(f(n), n**2) | This reads like a function definition, but it does not bind the symbols f and n and hence only makes sense as an equation involving free variables. @example@ @example@ Equal(Pow(2, Div(1,2)), NotElement(Sqrt(2), QQ)) | This equation is incorrect semantically, because it compares a number with a boolean value. A different function would be needed to assert the set membership property while returning the element instead of the boolean result. @example@pygrim: Grim in Python
Constructing and manipulating expressions
Basic usage:
>>> import pygrim >>> pygrim.Equal Equal >>> pygrim.Pi Pi >>> pygrim.Equal(pygrim.Pi - pygrim.Pi, 0) Equal(Sub(Pi, Pi), 0)
All Grim expressions are instances of the pygrim.Expr class. The Expr class overloads arithmetic operators in Python. However, the == and != operators in Python compare expressions, rather than creating Grim Equal and NotEqual expressions.
>>> 1 + pygrim.Pi ** 2 Add(1, Pow(Pi, 2)) >>> (1 + pygrim.Pi ** 2) == pygrim.Add(1, pygrim.Pow(pygrim.Pi, 2)) True >>> (1 + pygrim.Pi ** 2) == pygrim.Add(pygrim.Pow(pygrim.Pi, 2), 1) False
Expressions are immutable, and hashable.
>>> {pygrim.Pi : 3.14, pygrim.Sqrt(2) : 1.41} {Pi: 3.14, Sqrt(2): 1.41}
The statement from pygrim import * imports all builtin Grim symbols as Python variables. It also imports many useful predefined variables (like x). Since this risks generating conflicts with other namespaces, it is a good idea to import selectively:
>>> from pygrim import Expr, x, y, z
Some useful operations:
>>> x.is_atom() True >>> x.args() # None >>> x.head() # None >>> (x+y+z).is_atom() False >>> x+y+z Add(Add(x, y), z) >>> (x+y+z).head() Add >>> (x+y+z).args() (Add(x, y), z) >>> x.is_symbol() True >>> Expr(3).is_integer() True >>> int(Expr(3)) 3 >>> Expr("foo").is_text() True >>> list((2*x+3*y*z).subexpressions()) [Add(Mul(2, x), Mul(Mul(3, y), z)), Add, Mul(2, x), Mul, 2, x, Mul(Mul(3, y), z), Mul, Mul(3, y), Mul, 3, y, z] >>> list((2*x+3*y*z).subexpressions(unique=True)) [Add(Mul(2, x), Mul(Mul(3, y), z)), Add, Mul(2, x), Mul, 2, x, Mul(Mul(3, y), z), Mul(3, y), 3, y, z] >>> list((2*x+3*y*z).subexpressions_with_head(pygrim.Mul)) [Mul(2, x), Mul(Mul(3, y), z), Mul(3, y)] >>> list((2*x+3*y*z).symbols()) [Add, Mul, x, Mul, Mul, y, z] >>> list((2*x+3*y*z).symbols(unique=True)) [Add, Mul, x, y, z] >>> ((1+pygrim.Pi)**2).replace({pygrim.Pi : Expr(22) / 7}) Pow(Add(1, Div(22, 7)), 2)
Accessing FunGrim formulas
>>> import pygrim.formulas >>> e = pygrim.formulas.entries_dict["590136"] >>> e Entry(ID("590136"), Formula(Equal(Pi, Neg(Mul(ConstI, Log(-1)))))) >>> e.args()[1].args()[0].head() Equal >>> e.args()[1].args()[0].args() (Pi, Neg(Mul(ConstI, Log(-1))))
LaTeX output
>>> (Cos(Pi)+x/y).latex() '\\cos(\\pi) + \\frac{x}{y}'
Numerical evaluation
The .n() method provides numerical evaluation using Arb. It only works if Python-FLINT is installed.
>>> (Pi - 1).n(50) RealBall(Decimal("2.1415926535897932384626433832795028841971693993751"), Decimal("5.83e-51"))
By default, .n() returns a Grim expression representing a set that encloses the value of the input expression. The enclosure can also be returned as a Python-FLINT type:
>>> type((Pi - 1).n(30, as_arb=True)) <class 'flint.arb'>


Parse.ly Press Coverage – August 2013
Parse.ly made its funding announcement — a $5M series A, led by Grotech Ventures and with participation from FundersClub, Blumberg Capital, and ff Venture Capital. Read on for the full list of links to our coverage.
Here is some coverage from around the web:
- TechCrunch: Parse.ly Raises $5M For Predictive Analytics Platform That Helps Media Companies Decide What To Publish
- MediaPost: Parse.ly Raises $5 Million, Invests In Core Tech, Data
- The Daily Startup @ Wall Street Journal, VC Dispatch
- Washington Business Journal: Grotech leads $5 million round in analytics startup Parse.ly
- MarketingLand: Facebook Driving More Than 2x Twitter Traffic To Parse.ly’s News Clients
- GigaOM: Feedly dominating the post-Reader world, and other web-publishing insights from Parse.ly
- peHUB: Parse.ly raises $5M
- Parse.ly Blog: Parse.ly Investors Back the New Content Performance Authority
- The Next Web: A month after Google Reader vanishes, Feedly ranks as the top RSS traffic referrer
- VentureBeat: Parse.ly nabs $5 million to continue getting you to click on Grumpy Cat
- PSFK: Platform Tells Bloggers What To Write About Next [Video]
- memeburn: Life after Google Reader: yes, Feedly is still winning
- Brafton: Yahoo might be top web property, but Google still drives most traffic
- eMediaVitals: Publishing analytics startup Parse.ly releases first report on traffic drivers
- IPG Media Lab: Parse.ly Does Intelligent Tagging
- ContentStandard: Parse.ly Delivers Content Optimization for Online Publishers
More coming soon!


Keras example of supervised learning a NeuroGym task¶
NeuroGym is a comprehensive toolkit that allows training any network model on many established neuroscience tasks using Reinforcement Learning techniques. It includes working memory tasks, value-based decision tasks and context-dependent perceptual categorization tasks.
In this notebook we first show how to install the relevant toolbox.
We then show how to access the available tasks and their relevant information.
Finally we train an LSTM network on the Random Dots Motion task using standard supervised learning techniques (with Keras), and plot the results.
Installation when used on Google Colab¶
[ ]:
%tensorflow_version 1.x
# Install gym
! pip install gym
# Install neurogym
! git clone https://github.com/gyyang/neurogym.git
%cd neurogym/
! pip install -e .
Task, network, and training¶
[1]:
import warnings
import numpy as np
import neurogym as ngym
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, LSTM, TimeDistributed, Input
warnings.filterwarnings('ignore')
warnings.filterwarnings('default')
# Environment
task = 'PerceptualDecisionMaking-v0'
kwargs = {'dt': 100}
seq_len = 100
# Make supervised dataset
dataset = ngym.Dataset(task, env_kwargs=kwargs, batch_size=16,
seq_len=seq_len)
env = dataset.env
obs_size = env.observation_space.shape[0]
act_size = env.action_space.n
# Model
num_h = 64
# from https://www.tensorflow.org/guide/keras/rnn
xin = Input(batch_shape=(None, None, obs_size), dtype='float32')
seq = LSTM(num_h, return_sequences=True, time_major=True)(xin)
mlp = TimeDistributed(Dense(act_size, activation='softmax'))(seq)
model = Model(inputs=xin, outputs=mlp)
model.summary()
model.compile(optimizer='Adam', loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# Train network
steps_per_epoch = 2000
data_generator = (dataset() for i in range(steps_per_epoch))
history = model.fit(data_generator, steps_per_epoch=steps_per_epoch)
/Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:516: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_qint8 = np.dtype([("qint8", np.int8, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:517: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_quint8 = np.dtype([("quint8", np.uint8, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:518: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_qint16 = np.dtype([("qint16", np.int16, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_quint16 = np.dtype([("quint16", np.uint16, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_qint32 = np.dtype([("qint32", np.int32, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
np_resource = np.dtype([("resource", np.ubyte, 1)])
WARNING:tensorflow:From /Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
/Users/gryang/tf1/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_qint8 = np.dtype([("qint8", np.int8, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_quint8 = np.dtype([("quint8", np.uint8, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_qint16 = np.dtype([("qint16", np.int16, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:544: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_quint16 = np.dtype([("quint16", np.uint16, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:545: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
_np_qint32 = np.dtype([("qint32", np.int32, 1)])
/Users/gryang/tf1/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:550: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
np_resource = np.dtype([("resource", np.ubyte, 1)])
/Users/gryang/Dropbox/Code/MyPython/neurogym/neurogym/core.py:253: UserWarning: Warning: Time for period fixation 100.000000 lasts only one timestep. Agents will not have time to respond (e.g. make a choice) on time.
' time to respond (e.g. make a choice) on time.')
/Users/gryang/Dropbox/Code/MyPython/neurogym/neurogym/core.py:253: UserWarning: Warning: Time for period decision 100.000000 lasts only one timestep. Agents will not have time to respond (e.g. make a choice) on time.
' time to respond (e.g. make a choice) on time.')
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, None, 3)] 0
_________________________________________________________________
lstm (LSTM) (None, None, 64) 17408
_________________________________________________________________
time_distributed (TimeDistri (None, None, 3) 195
=================================================================
Total params: 17,603
Trainable params: 17,603
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:From /Users/gryang/tf1/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
7/2000 [..............................] - ETA: 5:35 - loss: 1.0581 - acc: 0.4196
/Users/gryang/Dropbox/Code/MyPython/neurogym/neurogym/core.py:253: UserWarning: Warning: Time for period fixation 100.000000 lasts only one timestep. Agents will not have time to respond (e.g. make a choice) on time.
' time to respond (e.g. make a choice) on time.')
/Users/gryang/Dropbox/Code/MyPython/neurogym/neurogym/core.py:253: UserWarning: Warning: Time for period decision 100.000000 lasts only one timestep. Agents will not have time to respond (e.g. make a choice) on time.
' time to respond (e.g. make a choice) on time.')
2000/2000 [==============================] - 106s 53ms/step - loss: 0.0569 - acc: 0.9835
Analysis¶
[2]:
# TODO: Make this into a function in neurogym
perf = 0
num_trial = 200
for i in range(num_trial):
env.new_trial()
obs, gt = env.obs, env.gt
obs = obs[:, np.newaxis, :]
action_pred = model.predict(obs)
action_pred = np.argmax(action_pred, axis=-1)
perf += gt[-1] == action_pred[-1, 0]
perf /= num_trial
print(perf)
0.895
[3]:
_ = ngym.utils.plotting.fig_(obs[0], action_pred[0], gt)
[ ]:


During this rotation, we learned about Arduino. Arduino platform that was created to provide a powerful tool to teach people about programing
with crucits. Not only are you able to change around the cricut without sodering, you can change the programs as well. For example, in one of the
projects I was able to change the speed of the motor by altering its rotation speed and directions. Here are images of the 17 Arduino projects I completed when I
finishing the Ardiuno's Kit Guide:


Introducing the concept of a class
First and foremost, classes help a programmer to organize his or her code. On a more abstract level, classes are one of the defining features of object oriented programming, so I find it easier to explain what a class is by explaining its relationship to Object Oriented Programming in general.
Finding classes of objects in real life
In the real world, almost everything around us can be thought of as an object. A chair is an object, a laptop is an object, a dog is an object. Thinking in these terms can make it easier to understand the world: An animal is an object. A dog is an object. A cat is an object. And these three objects are related in the sense that cats and dogs are animals. That type of relationship is helpful for us to consider when thinking about dogs and cats.
It also helps a person to program a big and complicated program if different parts of the program can be broken up into different "objects", and those objects can have clearly defined relationships. This brings us to the main point of this article: Classes. Classes are used to clearly define those relationships between different parts of a code.
Before this class concept is applied to the creation of a helpful program, many programming books and tutorials first apply the concept to silly examples from the real world. I will follow suit. Here I am going to create a Rapper class.
Our silly rapper class
In the real world, some might see a "rapper" as a relatively broad category,
and there may be more specific kinds of rappers within that class such as
"gangster rapper", "commercial rapper", "underground rapper", etc. But, before
we get into those specifics, the first step is to create a rapper class like so:
class Rapper
end
However, before a class can be used throughout a program, it must be "initialized".
It's kind of like how a rapper, before his sick flows can be shared with the
rest of the world, he must be signed to a record deal. The initialize method
looks like this:
def initialize(real_name)
if real_name == signed_to_major_label
@rapper = stage_name
else
broke_artist = real_name
end
end
That code can be used to create a new instance variable which is simply an example
of that class. Then, the instance variable can be used throughout the program. Or,
getting back to our corny analogy, the rapper is free to tour across the nation.
In this example, I also threw in a real_name
argument variable that
can accept a sring of the rappers real name, and then it can test whether that
rapper has been signed to a major label.
A class within a program may also include methods that can be used throughout that program.
Getting back to our analogy:
def spit_rhymes(words)
return rand(words) + "by #{rapper}"
end
def make_beats(record_samples)
return rand(record_samples) + "produced by #{rapper}"
end
def featured_on_slow_song(singer, song)
remix = song.map(verse) do |verse|
verse << spit_rhymes
end
return remix + "featuring #{@rapper}"
end
In the code above, three methods were created that each could be used inside of the Rapper class.
Typical of Ruby class methods, each of those methods includes an instance variable drawn from the
initialize method. Data can be created when one runs the initialize method:
drake = Rapper.new("Aubrey Graham")
meek_mill = Rapper.new("Robert Williams")
You may notice that when the two lines above call the initialize method, the result is stored in a variable.
That way, the class methods can be called on that variable, and the program will understand
that it needs to use the instance variable that was created when the intialize method was first run. Code like this:
drake.featured_on_slow_song("Joanna Newsom", "Sapokanikan")
Hopefully the use of a class is not lost on the analogy. But, classes are all about these dynamic relationships between objects, methods, and the data that passes between them.


BrdFeedr was created to be an ultra-simple Twitter timeline reader.
Launch a minimal browser window to display your user timeline. You will be asked to sign in with your Twitter account.
The windows app is under development and coming soon. This is the ultimate goal of this project -- to address the lack of desktop clients available for Win8.


Hi, I'm a NYC based Full Stack Web Developer with experience in React, Ruby, Python, JavaScript,HTML and CSS.
I get a sense of thrill learning new things, because the more I understand something, the more
creatively I can develop. My favorite languages are Python and JavaScript, and I especially enjoy working with frontend technology (currently a toss-up between React or Vue).
Outside of programming I enjoy hiking, reading any sci-fi book, or destroying people in Counter-Strike and PUBG.
ImGir is a full-stack web application inspired by Imgur with an "Invader Zim" twist. It utilizes Ruby on Rails on the backend, a PostgreSQL database, and React.js with a Redux architectural framework on the frontend. Users are able to submit funny photos and have them viewed and commented on them by the community
View Code View Project


We aggregate platforms!
- aggregate vertical platforms
- maximize bricks-and-clicks models
- utilize 24/7 portals
- innovate distributed schemas
- revolutionize distributed relationships
- deliver synergistic e-tailers
- empower rich users
- benchmark clicks-and-mortar synergies
- synthesize interactive markets
- maximize e-business synergies
- orchestrate efficient architectures
- monetize virtual vortals
- transform B2B markets
- repurpose seamless technologies


take-off
Hendrik Harlichs
Contact
Back
Login
Email address
Password
Show
Email and password don't match.
Sign In


FORD CARS INDIA
Home
New
Shop
Featured
Contact
WELCOME TO OUR FAMILY
GO FURTHER
LET'S TAKE A LOOK TO OUR CARS
BOOKINGS
FORD ASPIRE 2020
F O R D
FREESTYLE
LIMITED!!
F O R D
MUSTANG
LIMITED!!
FORD FIGO 2020
FORD 2020 SUV'S
JOIN OUR FORD FAMILY
GRAB YOUR LIMITED DIWALI DEAL WITH EXCITING OFFERS.
JOIN


Pronto CMS
Awesome! It's another website powered by Pronto CMS!
Configure the website here and you're ready to go.
You can always edit these settings later in "web.config".
Awesome! It's another website powered by Pronto CMS!
Configure the website here and you're ready to go.
You can always edit these settings later in "web.config".


In previous sections we've looked at the US used car market in terms of car features, price and sales volume. But we cannot get a grasp the whole picture without considering geographical factors. Is there a geographical difference in used car sales volume across the United States? We reveal some interesting answers here. Combining geographical features, we give some explanations for our findings as well.
In short, this section answers the following subquestions:
Now, let's dive into charts and numbers.
Figure 3.1 Sale volume Distribution and Popular Body Style by State
In the map, we can click the blue markers to explore the top three popular body styles in each state. SUV style has the greatest sales volume in almost all states. Our data table shows that Hawaii, Maryland and New York are the only three states where Sedan rather than SUV is the most popular. But SUV still ranks top two in the three states. Sedan ranks the second most popular among most states. Crew Cab Pickup is usually the third most popular. Coupe as well as Sedan appears as the third most popular body style in a few states. Hatchback appears once as the third most popular in Hawaii. SUV, Sedan, Crew Cab Pickup, Coupe and Hatchback are the only five body styles that may appear as the top three popular.
If we uncheck the box at the upper right corner, we can see the sales volume distribution across states more clearly.
A darker color indicates a greater sales volume of used cars. Three states, Texas, California and Florida outnumber other states with considerable used car sales volume over a hundred thousand. Their sales volumes are remarkably greater than the rest of the states.
What are the factors that account for the geographical difference in sales volume?
Figure 3.2 Sales Volume vs Non Auto Commute Percentage and Population
Here we have a hypothesis that the percentage of workers who use non auto transportation means to commute is negatively related with used car sales volume whereas population is positively related with sales volume. Non auto transportation means include public transportation, walk, taxicab, motorcycle, bicycle, work at home and other transportation means that does not involve using a private auto (taxicab excluded). Figure 3.2 above reveals if the hypothesis is true not false.
The vertical axis indicates the percentage of workers who use non auto transportation means to commute. The horizontal axis indicates the population of that state. The size of the bubble indicates the sales volume of that state. There are some tools for viewing the plot located on the right side of the figure, such as wheel zoom, box zoom, crosshair (showing auxilliary lines perpendicular to the two axes) and hover (showing the label when hovering on the data point). Hovering over the bubble we can see the name, population, non auto commute percentage and sales volume of a certain state. Also, we can choose the second tool, box zoom, to choose a certain area in the figure and take a closer look.
Figure 3.3 Sales Volume vs GDP
From Figure 3.3, states with a greater gross domestic product tend to have higher sales volume of used cars. The p-value for the regression is less than 0.05, and R-Squared is 0.74, which means that state GDP can predict 74% of the sales volume in that state. Similarly, we can use the tools located on the right side of the figure to better explore the figure.
Also, note that GDP is positively related to population. No wonder that GDP can largely explain the sales volume since we've seen in Figure 3.2 that greater state population indicates a higher sales volume.


BAD BOY BUBBY A film review by Phil Herring Copyright 1994 Phil Herring
Writer: Rolph De Heer Director: Rolph De Heer Actors: Nicholas Hope Carmel Johnson Claire Benito
The theme of a person locked away for their entire life, and then by chance released into the wide world, has been explored fairly often in the past (BEING THERE and THE ENIGMA OF KASPAR HAUSER spring to mind), and they generally fall into two categories: either the person will succeed in the experience, or the world will destroy them.
But in the low-budget Australian film BAD BOY BUBBY, this is not really the main issue.  He is, to all intents and purposes, an infant. Then one day he seizes his freedom, and escapes into the black night of the industrial suburbs of Adelaide. The rest is part adventure, part tragedy, and part comedy. It's also very intense, confronting and discomforting. Bubby is the target of hatred, charity, loathing and love, and this emotional roller coaster closely parallels the experience of the audience, who are subjected to black, ironic humour mixed with images that openly defy the conventions of commercial cinema.
And despite the well-worn theme, the film manages to keep you in your seat. It doesn't have the usual monotonic form of a mainstream film (an opening exposition, followed by a steady, direct run to a clear resolution); instead, it vacillates between joy and despair. Bubby has good days and bad days; the audience gets to ride up and down with him.
 In the end, he is resilient, and the audience sees him grow up very quickly without losing his identity. This, in spite of all the cruelty that he experiences and inflicts.
And the visual imagery in the film is amazing. It is almost wholly bleak, dark, and at times positively Hogarthian, with a lot of attention paid to the texture of dirty skin, the sagging of folds of fat, the dull fall of artificial light, and the patina of used, worn surfaces. It's a visual experience that you can also feel and smell, and it's both repellent and oddly appealing.
It must be said, though, that not everybody will enjoy this film. It's probably unconventional enough to discomfort most viewers, and the first forty minutes are set in a tiny, claustrophobic space, and are quite difficult to watch at times; plus the film directly addresses the matter of what is beautiful, and the way that women are used in movies. (Not in any overt way, mind you; it's just there if you want to look for it.) And on the subject of sex, this film has a lot of it, and it's quite explicit, but the way it operates on the viewer is subtle and strange. It isn't simple eroticism.
There is also the matter of the final resolution, which I found somewhat disappointing; on the other hand, I think that it was unavoidable, given where the film was going. Some of the acting is also a tad uninspired, possibly because those actors weren't experienced.
In summary, this low-budget film is an amazing experience; its good points overwhelm its flaws, and I can only say that it's thoroughly watchable, and probably headed for a cult following.
-- Phil.
(c) 1994 Rev. Dr. Phil Herring<EMAIL_ADDRESS>- Church of the Sacred Dial Tone, Wollongong, Australia - Permission is hereby granted to: 1. quote the original material in this article when posting responses to it via Usenet or when sending responses to myself or others via electronic mail; and 2. copy the entire article intact via Usenet for the purposes of transmitting the article to other Usenet sites. All other reproduction of this article constitutes a breach of copyright laws and will be subject to both civil and criminal action.
.
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Solo Exhibitions
{% include components/bio-solo-expos.html %}
Group Exhibitions
{% include components/bio-group-expos.html %}
Awards, Grants & Residencies
{% include components/bio-awards.html %}
Performatic talks, Presentations & Conferences
{% include components/bio-talks.html %}
Workshops & Directed Activities
{% include components/bio-workshops.html %}
Education
Art education
{% include components/bio-art-edu.html %}
Professional education
{% include components/bio-pro-edu.html %}


--- title: Kotodaman Word Stats description: Find out the best combination. permalink: / layout: layout ---