Kind system - sympy/sympy GitHub Wiki

Kind system was first introduced in version 1.8 by PR #20549. Its purpose is to separate the mathematical type and Python type of a SymPy object.

In SymPy, objects with different mathematical types have different Python types. For example, Symbol class represents arbitrary scalar and Add represents addition between scalars, while MatrixSymbol represents arbitrary matrix and MatAdd represents addition between matrices.

The problem of this approach is that the number of classes grows in square order. Currently, numerous classes (e.g. Integral, Piecewise) supports only scalar, and in order to support matrix we need matrix versions of them (e.g. MatIntegral, MatPiecewise). And if we want to support another type like tensor, we need to implement new versions of these classes all over again.

This restriction can be alleviated by using kind system. In this new design, mathematical type of an object is distinguished by kind attribute, instead of its Python class. For example, a numerical object has singleton NumberKind instance as its kind, and matrix object has MatrixKind.

In the kind system, the class of an object merely represents its Python implementation. A single Add class can represent scalar addition and matrix addition depending on the kind of its arguments, since these two are both algebraic group operations. However, Symbol and MatrixSymbol need to be distinguished because the latter needs shape information.

In order to support the evaluation of Add with different kinds, the evaluation logic must be defined by the kind instance. For example, we need to define methods such as NumberKind._eval_Add() which treats 0 as identity element, and MatrixKind._eval_Add() which treats zero matrix as identity element. Add class should call one of these methods by the kind of its elements.

One major obstacle in this approach is that we cannot use kind-dependent attributes (i.e. MatAdd.shape) anymore. This can be resolved by defining a shape() function which returns the shape of any matrix-kind object, and replace the shape attribute with this function over entire SymPy codebase.

One more important point for kind system is that we need to support the operations between different kinds. Currently, a single MatMul class deals with matrix-matrix multiplication and scalar-matrix multiplication altogether. (Perhaps this is an design error and we need two separate ScalarMul and BilinearProduct classes.) In order to make Mul do this, we need to define the NumberKind x MatrixKind -> MatrixKind rule. This can be done by kind dispatching system, which is already supported.

Finally, it must be stressed that Kind should not be combined with complicated set theory logic. This is to facilitate the determination of the kind of associative operation with very large number of arguments. For example, integer, irrational number and complex number should have just NumberKind.

Please refer to the mailing list for further discussion on this topic.