Cadabra
Computer algebra system for field theory problems
Files | Functions
Python Core

Module Description

Python wrapper around the C++ core module.

This wrapper makes the entire functionality of Cadabra accessible from Python. This consists of two parts. One is core/cadabra2_defaults.py, which is a pure-python file. It contains the display function to show Cadabra objects to the user in a UI-independent way (e.g. switching between a text representation on the command line and a LaTeX representation when running in a notebook). The other part are the various files in core/pythoncdb, which build the cadabra2 module for python, to be imported with 'from cadabra2 import *'.

The Python module has functionality to import Cadabra notebooks using standard Python import syntax. This functionality is part of the Notebooks and packages module and described there.

Files

file  cadabra2_defaults.py
 Cadabra2 pure Python functionality.
 

Functions

void pull_in (std::shared_ptr< cadabra::Ex > ex, cadabra::Kernel *)
 Replace any objects of the form '@(...)' in the expression tree by the python expression '...' if it exists. More...
 
void run_python_functions (std::shared_ptr< cadabra::Ex > ex, cadabra::Kernel *)
 Run all functions in the given expression which are available in the Python scope. More...
 
template<class Algo >
Ex_ptr cadabra::apply_algo_base (Algo &algo, Ex_ptr ex, bool deep, bool repeat, unsigned int depth, bool pre_order=false)
 Generic internal entry point for the Python side to execute a C++ algorithm. More...
 
template<class Algo , typename... Args, typename... PyArgs>
void cadabra::def_algo (pybind11::module &m, const char *name, bool deep, bool repeat, unsigned int depth, PyArgs... pyargs)
 Method to declare a Python function with variable number of arguments, and make that call a C++ algorithm as specified in the Algo template parameter. More...
 
template<class Algo , typename... Args, typename... PyArgs>
void cadabra::def_algo_preorder (pybind11::module &m, const char *name, bool deep, bool repeat, unsigned int depth, PyArgs... pyargs)
 Method to declare a Python function with variable number of arguments, and make that call a C++ algorithm as specified in the Algo template parameter. More...
 
bool cadabra::Ex_compare (Ex_ptr, Ex_ptr)
 Comparison operator for Ex objects in Python. More...
 
Ex_ptr cadabra::Ex_add (const Ex_ptr ex1, const ExNode ex2)
 Add two expressions, adding a top-level '\sum' node if required. More...
 
Ex_ptr cadabra::Ex_mul (const Ex_ptr ex1, const Ex_ptr ex2)
 Multiply two expressions, adding a top-level '\prod' node if required. More...
 
Ex_ptr cadabra::Ex_sub (const Ex_ptr ex1, const ExNode ex2)
 Subtract two expressions, adding a top-level '\sum' node if required. More...
 
Ex_ptr cadabra::fetch_from_python (const std::string &nm)
 Fetch an Ex object from the Python side using its Python identifier. More...
 
std::string cadabra::Ex_as_str (Ex_ptr)
 Generate the Python str() and repr() representation of the Ex object. More...
 
std::string cadabra::Ex_as_latex (Ex_ptr)
 The Python 'print' function always calls the 'str' member on objects to be printed. More...
 
Kernelcadabra::create_scope ()
 Setup of kernels in current scope, callable from Python. More...
 
Kernelcadabra::get_kernel_from_scope ()
 Get a pointer to the currently visible kernel. More...
 

Function Documentation

◆ apply_algo_base()

template<class Algo >
Ex_ptr cadabra::apply_algo_base ( Algo &  algo,
Ex_ptr  ex,
bool  deep,
bool  repeat,
unsigned int  depth,
bool  pre_order = false 
)

Generic internal entry point for the Python side to execute a C++ algorithm.

This gets called by the various apply_algo functions below, which in turn get called by the def_algo functions.

◆ create_scope()

Kernel * cadabra::create_scope ( )

Setup of kernels in current scope, callable from Python.

When the decision was made to graft Cadabra onto Python, a choice had to be made about how Python variable scope would influence the visibility of Cadabra properties. It clearly makes sense to be able to declare properties which only hold inside a particular function. However Cadabra expressions and properties do not directly correspond to Python objects. Rather, declaring a property is more like a function call into the Cadabra module, which leaves its imprint on the state of the C++ part but does not change anything on the Python side, as you typically do not assign the created property to a Python symbol. Therefore, properties do not naturally inherit Python's scoping rules (this is different from e.g.~SymPy, in which mathematical objects are always in one-to-one correspondence with a Python object). A more fundamental problem is that properties can be attached to patterns, and those patterns can involve more than just the symbols which one passes into a function.

In order to not burden the user, properties are therefore by default global variables, stored in a single global Cadabra object __cdbkernel__ which is initialised at import of the Cadabra module. If you add new properties inside a function scope, these will go into this already existing global property list by default. If you want to create a local scope for your computations, create a new __cdbkernel__ as in

def fun():
[your code here]
Kernel * create_scope()
Setup of kernels in current scope, callable from Python.
Definition: py_kernel.cc:22
__cdbkernel__
Definition: cadabra2_defaults.py:21
Functions to handle the exchange properties of two or more symbols in a product.
Definition: Adjform.cc:83
void fun(int *&p)
Definition: passing.cc:6

Now computations will not see the global properties at all. If you want to import the global properties, use instead

def fun():
[your code here]
Kernel * create_scope_from_global()
Definition: py_kernel.cc:28

It is crucial that the __cdbkernel__ symbol is referenced from within Python and visible to the bytecompiler, because it is not possible to create new variables on the local stack at runtime. Internally, the second version above fetches, at runtime, the __cdbkernel__ from the globals stack, copies all properties in there into a new kernel, and returns the latter.

Both versions above do populate the newly created kernel with Cadabra's default properties. If you want a completely clean slate (for e.g.~testing purposes, or because you really do not want default rules for sums and products), use

def fun():
[your code here]
Kernel * create_empty_scope()
Definition: py_kernel.cc:35

Note that in all these cases, changes to properties remain local and do not leak into the global property list.

All Cadabra algorithms, when called from Python, will first look for a kernel on the locals stack (i.e.~what locals() produces). If there is no kernel available locally, they will then revert to using the global kernel.

◆ def_algo()

template<class Algo , typename... Args, typename... PyArgs>
void cadabra::def_algo ( pybind11::module &  m,
const char *  name,
bool  deep,
bool  repeat,
unsigned int  depth,
PyArgs...  pyargs 
)

Method to declare a Python function with variable number of arguments, and make that call a C++ algorithm as specified in the Algo template parameter.

This will make the algorithm traverse post-order, that is to say, first on the innermost child (or leaf) of an expression tree, and then, if that fails, on parent nodes, and so on.

◆ def_algo_preorder()

template<class Algo , typename... Args, typename... PyArgs>
void cadabra::def_algo_preorder ( pybind11::module &  m,
const char *  name,
bool  deep,
bool  repeat,
unsigned int  depth,
PyArgs...  pyargs 
)

Method to declare a Python function with variable number of arguments, and make that call a C++ algorithm as specified in the Algo template parameter.

In contrast to def_algo, this one will apply the algorithm in pre-order traversal style, that is, it will first attempt to apply on a node itself before traversing further down the child nodes and attempting there.

◆ Ex_add()

Ex_ptr cadabra::Ex_add ( const Ex_ptr  ex1,
const ExNode  ex2 
)

Add two expressions, adding a top-level '\sum' node if required.

◆ Ex_as_latex()

std::string cadabra::Ex_as_latex ( Ex_ptr  )

The Python 'print' function always calls the 'str' member on objects to be printed.

This one is required to produce output which looks readable but is also still valid input. In order to produce proper LaTeX output, this is therefore not the right function to use, because Cadabra only reads a restricted subset of LaTeX (for instance, we output spacing commands like '\,' but do not accept it on input). So we have a separate latex() member on each object, which internally uses DisplayTeX to do the actual printing.

◆ Ex_as_str()

std::string cadabra::Ex_as_str ( Ex_ptr  ex)

Generate the Python str() and repr() representation of the Ex object.

◆ Ex_compare()

bool cadabra::Ex_compare ( Ex_ptr  ,
Ex_ptr   
)

Comparison operator for Ex objects in Python.

Since comparison operators need a Properties object, we cannot have such operator== things in C++, but we can in Python since we can get the kernel in the current scope.

◆ Ex_mul()

Ex_ptr cadabra::Ex_mul ( const Ex_ptr  ex1,
const Ex_ptr  ex2 
)

Multiply two expressions, adding a top-level '\prod' node if required.

◆ Ex_sub()

Ex_ptr cadabra::Ex_sub ( const Ex_ptr  ex1,
const ExNode  ex2 
)

Subtract two expressions, adding a top-level '\sum' node if required.

◆ fetch_from_python()

Ex_ptr cadabra::fetch_from_python ( const std::string &  nm)

Fetch an Ex object from the Python side using its Python identifier.

◆ get_kernel_from_scope()

Kernel * cadabra::get_kernel_from_scope ( )

Get a pointer to the currently visible kernel.

◆ pull_in()

void pull_in ( std::shared_ptr< cadabra::Ex ex,
cadabra::Kernel kernel 
)

Replace any objects of the form '@(...)' in the expression tree by the python expression '...' if it exists.

Rename dummies to avoid clashes.

◆ run_python_functions()

void run_python_functions ( std::shared_ptr< cadabra::Ex ex,
cadabra::Kernel kernel 
)

Run all functions in the given expression which are available in the Python scope.