FLINT3.7.0-dev
Module · 160 functions

fexpr.h

#include <flint/fexpr.h>

This module implements symbolic expressions. An expression is either an atom or a function call:

  • an atom is an integer (such as 0 or -34), a symbol (such as x, Mul or SomeUserNamedSymbol; symbols should be valid C identifiers) or a string (such as "Hello, world!"; ASCII only for now);
  • a function call e_0(e_1, \ldots, e_n) consists of expressions e_0, \ldots, e_n, where e_0 is usually, but not necessarily, a symbol.

What an expression means depends on how its symbols are interpreted. A large set of builtin symbols with a standard mathematical meaning is defined in fexpr_builtin.h: with it, Mul(3, Add(Neg(x), y)) denotes 3 \cdot (-x + y) for variables x and y. Builtin symbols are used for conversions to and from ca.h numbers (ca_get_fexpr, ca_set_fexpr), qqbar.h numbers (qqbar_get_fexpr_formula and related functions), polynomials and matrices, and for LaTeX output. The guide Building and printing expressions shows how to build, inspect and print expressions.

Guides#

Design#

Symbolic expressions are a data exchange format rather than a data structure for heavy computation: functions that compute with expressions typically convert them to a dedicated type, such as polynomials, and convert the result back. For the same reason, expressions cannot contain arbitrary binary objects such as fmpz_poly_t or ca_t values as atoms. To put such an object into an expression, represent it structurally with atoms and calls (for example a polynomial as a list of coefficients or as an arithmetic expression), introduce a placeholder symbol together with a separate table of values, or, less advisably, encode it in a string.

An fexpr_t is stored in flat-packed form: a single array of words (ulong) without internal pointers. The first word is a header that gives the type of the expression and its total size in words. Small integers, builtin symbols, and symbols and strings of at most FEXPR_SMALL_SYMBOL_LEN characters fit entirely into the header; larger atoms store their data in the following words. A function call stores its header followed by e_0, e_1, \ldots, e_n packed contiguously; for more than four arguments, an index of word offsets follows the header so that arguments can be located quickly.

This has several consequences:

  • memory management is trivial, copying an expression copies an array, and testing two expressions for structural equality compares arrays;
  • combining expressions into a call concatenates arrays;
  • expressions can be exchanged freely between threads, and between machines with the same word size and byte order;
  • repeated subexpressions cannot share memory (introduce local symbols with Where for this);
  • extracting a subexpression for modification requires a copy, although read-only access is free with views (see fexpr_view_arg);
  • modifying a part of an expression rebuilds the whole expression, so building an expression incrementally, for example a sum by repeated binary Add, costs O(n^2); build balanced expressions, or a single call such as Add with many arguments, instead.

Types and macros#

A symbolic expression. The structure has the fields data (a pointer to the array of words) and alloc (the number of allocated words, 0 for a view). An fexpr_t is an array of one structure, so it is passed by reference.

Aliases for fexpr_struct * and const fexpr_struct *, used for arrays of expressions.

A vector of expressions with managed length, with the fields entries (an fexpr_ptr), length and alloc.

fexpr_vec_entry(vec, i)

Expands to a pointer to the entry with index i of vec.

The type codes stored in the low FEXPR_TYPE_BITS = 4 bits of the header word: small atoms stored in the header, large integers (with a sign) and large symbols and strings stored in the following words, and function calls with 0 to 4 arguments or with an argument count stored after the header.

Macros for decoding header words: the type and the size in words of the expression with header head, the size of a header (one word), the range of integers stored in the header (about \pm 2^{\mathtt{FLINT\_BITS} - 5}), the maximum length of a symbol or string stored in the header (\mathtt{FLINT\_BITS}/8 - 1 characters), and the index of a builtin symbol stored in the header.

Memory management#

void fexpr_init(fexpr_t expr)

Initialises expr and sets it to the integer 0.

void fexpr_clear(fexpr_t expr)

Clears expr, freeing its memory.

Allocates an array of len expressions initialised to 0, or clears the len expressions of vec and frees the array.

void fexpr_fit_size(fexpr_t expr, slong size)

Ensures that expr has room for size words, growing the allocation to at least twice its size if it must grow.

void fexpr_set(fexpr_t res, const fexpr_t expr)

Sets res to a copy of expr.

Swaps a and b in constant time.

Size information#

Returns the depth of expr as a tree: 1 for an atom, and one more than the largest depth of the function and the arguments for a call.

Returns the number of atoms in expr, counted with repetition.

Returns the size of expr in words or in bytes, or the number of bytes allocated for it. The counts exclude the structure itself; add sizeof(fexpr_struct) for the size of the whole object.

Comparisons#

int fexpr_equal(const fexpr_t a, const fexpr_t b)

Returns whether a and b are the same expression (structural equality, a comparison of the word arrays).

int fexpr_equal_si(const fexpr_t expr, slong c)
int fexpr_equal_ui(const fexpr_t expr, ulong c)

Returns whether expr is the integer atom c.

Returns a hash of expr; equal expressions have equal hashes.

int fexpr_cmp_fast(const fexpr_t a, const fexpr_t b)

Compares a and b in a total order based on the internal representation, returning -1, 0 or 1. The order is fast and suitable for sorting and binary search, but has no mathematical meaning.

Atoms#

int fexpr_is_integer(const fexpr_t expr)
int fexpr_is_symbol(const fexpr_t expr)
int fexpr_is_string(const fexpr_t expr)
int fexpr_is_atom(const fexpr_t expr)

Returns whether expr is an integer, a symbol, a string, or any atom.

int fexpr_is_zero(const fexpr_t expr)

Sets res to the integer 0, or returns whether expr is the integer 0.

Returns whether expr is a negative integer atom.

void fexpr_set_fmpz(fexpr_t res, const fmpz_t c)

Sets res to the integer atom c.

int fexpr_get_fmpz(fmpz_t res, const fexpr_t expr)

If expr is an integer atom, sets res to its value and returns 1; otherwise returns 0 and leaves res unchanged.

Sets res to the builtin symbol with index id, for example FEXPR_Pi (see fexpr_builtin.h).

Returns whether expr is the builtin symbol with index id, or any builtin symbol.

void fexpr_set_symbol_str(fexpr_t res, const char * s)

Sets res to the symbol with name s. If s is the name of a builtin symbol, the builtin symbol is created, so that fexpr_set_symbol_str(e, "Pi") and fexpr_set_symbol_builtin(e, FEXPR_Pi) give the same expression.

char * fexpr_get_symbol_str(const fexpr_t expr)

Returns a newly allocated string with the name of the symbol expr, which the caller must free with flint_free. Throws an exception if expr is not a symbol.

void fexpr_set_string(fexpr_t res, const char * s)
char * fexpr_get_string(const fexpr_t expr)

Sets res to the string atom with content s, or returns a newly allocated copy of the string atom expr, which the caller must free with flint_free.

Input and output#

The plain-text form of an expression is the notation used throughout this documentation: integers in decimal, symbols by name, strings in double quotes, and calls as f(e1, e2, ...).

void fexpr_write(calcium_stream_t stream, const fexpr_t expr)
void fexpr_print(const fexpr_t expr)
char * fexpr_get_str(const fexpr_t expr)

Writes expr in plain text to stream, prints it to standard output, or returns it as a newly allocated string to be freed with flint_free.

More
char * fexpr_get_decimal_str(const fexpr_t expr, slong digits, ulong flags)

Returns a newly allocated string with a decimal approximation of the value of expr with digits significant digits, or "?" if the expression cannot be evaluated numerically. The expression is evaluated in ball arithmetic with increasing precision (up to a few thousand bits); integers, the constants Pi, NumberI, NumberE, Euler, CatalanConstant and GoldenRatio, arithmetic, roots, elementary functions, and some special functions such as Gamma, Erf, RiemannZeta, the Bessel and Airy functions are supported. flags is reserved and should be 0.

LaTeX output#

void fexpr_write_latex(calcium_stream_t out, const fexpr_t expr, ulong flags)
void fexpr_print_latex(const fexpr_t expr, ulong flags)
char * fexpr_get_str_latex(const fexpr_t expr, ulong flags)

Writes a LaTeX rendering of expr to out, prints it to standard output, or returns it as a newly allocated string to be freed with flint_free. Builtin symbols are rendered with standard mathematical notation (see fexpr_builtin.h); other calls are rendered as function applications. String atoms are not escaped.

Flags for LaTeX output. FEXPR_LATEX_SMALL produces more compact formulas, in particular fractions written inline as p/q rather than \displaystyle \frac{p}{q}; it is enabled automatically in subscripts, superscripts and some other parts of formulas. FEXPR_LATEX_LOGIC uses symbols for logical operators such as Not, And and Or, which are rendered as words by default.

Function call structure#

Returns the number of arguments n of the call f(e_1, \ldots, e_n), or -1 if expr is an atom.

void fexpr_func(fexpr_t res, const fexpr_t expr)
void fexpr_view_func(fexpr_t res, const fexpr_t expr)

For a call f(e_1, \ldots, e_n), sets res to a copy of f, or to a view of it. A view shares the data of expr (it has alloc = 0): it must not be initialised before nor cleared after use, must not be modified, and is valid only as long as expr is not modified or cleared.

void fexpr_arg(fexpr_t res, const fexpr_t expr, slong i)
void fexpr_view_arg(fexpr_t res, const fexpr_t expr, slong i)

For a call f(e_1, \ldots, e_n), sets res to a copy of, or a view of, the argument e_{i+1} (indices start at 0 and must satisfy 0 \le i < n). Throws an exception if expr is an atom. Access takes O(1) steps for calls with more than four arguments, thanks to the index.

Advances a view of e_i (or of f) in a call to a view of the next argument e_{i+1} (or of e_1). It may be called on a view of the last argument provided that the result is not used.

int fexpr_is_builtin_call(const fexpr_t expr, slong id)

Returns whether expr is a call f(\ldots) where f is the builtin symbol with index id, or any builtin symbol.

Construction#

void fexpr_call0(fexpr_t res, const fexpr_t f)
void fexpr_call1(fexpr_t res, const fexpr_t f, const fexpr_t x1)
void fexpr_call2(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2)
void fexpr_call3(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3)
void fexpr_call4(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3, const fexpr_t x4)
void fexpr_call_vec(fexpr_t res, const fexpr_t f, fexpr_srcptr args, slong len)

Sets res to the call f(x_1, \ldots, x_n), with the arguments given explicitly or as the array args of length n = len. The output must not be the same object as any input.

void fexpr_call_builtin2(fexpr_t res, slong f, const fexpr_t x, const fexpr_t y)

Sets res to the call f(x) or f(x, y), where f is the builtin symbol with index f. Here res may be the same object as an argument.

Subexpressions and replacement#

int fexpr_contains(const fexpr_t expr, const fexpr_t x)

Returns whether x occurs as a subexpression of expr (including expr itself).

int fexpr_replace(fexpr_t res, const fexpr_t expr, const fexpr_t x, const fexpr_t y)
int fexpr_replace2(fexpr_t res, const fexpr_t expr, const fexpr_t x1, const fexpr_t y1, const fexpr_t x2, const fexpr_t y2)
int fexpr_replace_vec(fexpr_t res, const fexpr_t expr, const fexpr_vec_t xs, const fexpr_vec_t ys)

Sets res to expr with every occurrence of the subexpression x replaced by y (or of the entries of xs by the corresponding entries of ys, which must have the same length), simultaneously and without rescanning the replacements. Returns whether any replacement was made. res may be the same object as expr but not as the other inputs.

Arithmetic expressions#

void fexpr_set_fmpq(fexpr_t res, const fmpq_t x)

Sets res to the rational number x: an integer atom if the denominator is 1, and otherwise Div(p, q).

void fexpr_set_arf(fexpr_t res, const arf_t x)
void fexpr_set_d(fexpr_t res, double x)

Sets res to an expression for the exact value of the floating-point number x = m \cdot 2^e (m odd): an integer if 0 \le e \le 20, a fraction Div(m, 2^-e) if -8 \le e < 0, and otherwise Pow(2, e), Neg(Pow(2, e)) or Mul(m, Pow(2, e)). Infinities are written as Infinity and Neg(Infinity), NaN as Undefined.

void fexpr_set_re_im_d(fexpr_t res, double x, double y)

Sets res to an expression for the complex number x + yi, built with fexpr_set_d, NumberI, Mul and Add (omitting zero parts).

void fexpr_neg(fexpr_t res, const fexpr_t a)
void fexpr_add(fexpr_t res, const fexpr_t a, const fexpr_t b)
void fexpr_sub(fexpr_t res, const fexpr_t a, const fexpr_t b)
void fexpr_mul(fexpr_t res, const fexpr_t a, const fexpr_t b)
void fexpr_div(fexpr_t res, const fexpr_t a, const fexpr_t b)
void fexpr_pow(fexpr_t res, const fexpr_t a, const fexpr_t b)

Sets res to the expression Neg(a), Add(a, b), Sub(a, b), Mul(a, b), Div(a, b) or Pow(a, b), without any simplification.

Returns whether expr is a call of one of the arithmetic operators Pos, Neg, Add, Sub, Mul or Div.

Sets nodes to the subexpressions of expr that are the leaves when expr is viewed as an arithmetic expression: expr is built from integers and the elements of nodes by nested applications of Pos, Neg, Add, Sub, Mul, Div and Pow with an integer exponent. Each node appears once; the nodes are not sorted.

int fexpr_get_fmpz_mpoly_q(fmpz_mpoly_q_t res, const fexpr_t expr, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx)

Sets res to expr viewed as a rational function of the subexpressions in vars, which are treated as independent indeterminates, and returns 1. The length of vars must equal the number of variables of ctx; fexpr_arithmetic_nodes gives a suitable vector. Returns 0 if a subexpression is neither an arithmetic operation nor an entry of vars, on overflow (too many terms or too large exponents), or on division by zero.

More
void fexpr_set_fmpz_mpoly(fexpr_t res, const fmpz_mpoly_t poly, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx)
void fexpr_set_fmpz_mpoly_q(fexpr_t res, const fmpz_mpoly_q_t frac, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx)

Sets res to an expression for the polynomial poly (or the rational function frac), with the entries of vars substituted for the variables. The length of vars must equal the number of variables of ctx; if vars is NULL, default symbols are used.

int fexpr_expanded_normal_form(fexpr_t res, const fexpr_t expr, ulong flags)

Sets res to the expanded normal form of expr as a formal rational function of its non-arithmetic subexpressions, and returns 1 (0 on failure, see fexpr_get_fmpz_mpoly_q). The nodes are found with fexpr_arithmetic_nodes and sorted with fexpr_cmp_fast, expr is converted with fexpr_get_fmpz_mpoly_q and converted back with fexpr_set_fmpz_mpoly_q. flags is reserved and should be 0.

Vectors#

Initialises vec as a vector of len expressions equal to 0, or clears it.

Prints the entries of F to standard output, comma-separated in square brackets, without a newline.

Swaps x and y in constant time.

Ensures that vec has room for len entries, without changing its length.

void fexpr_vec_set(fexpr_vec_t dest, const fexpr_vec_t src)

Sets dest to a copy of src.

Appends a copy of f to vec.

Returns the index of an entry of vec equal to f, appending f first if there is none. The search is linear.

Sets the length of vec to len, appending zeros or truncating as needed.

Sorts the len entries of vec with the order of fexpr_cmp_fast.

Internal functions#

slong _fexpr_size(const ulong * expr)
int _fexpr_is_integer(const ulong * expr)
int _fexpr_is_symbol(const ulong * expr)
int _fexpr_is_string(const ulong * expr)
int _fexpr_is_atom(const ulong * expr)

Versions of fexpr_size and the atom predicates that take a pointer to the header word of an expression.

The following functions write a call of a particular builtin symbol in LaTeX. They are the writer callbacks referenced by the table of builtin symbols (fexpr_builtin_table) and are called by fexpr_write_latex; the argument expr must be a call of a symbol for which the writer is intended, with arguments of the expected form. All have the arguments of fexpr_write_latex.

Generic forms: a function application f(x_1, \ldots, x_n), a symbol with subscripts f_{x_1, \ldots, x_n} (used for the indexed Greek and Latin variable symbols), and a subscripted function application f_{x_1}(x_2, \ldots).

Operators: infix relations and operators (such as Equal, Less or Element), products, quotients (as fractions, or inline with FEXPR_LATEX_SMALL), unary minus and plus, sums, differences, powers, e^x, and factorials, with parentheses inserted as needed.

Operators binding variables through For: sums and products, divisor sums, integrals, limits, residues and derivatives.

Special functions with an optional derivative order as last argument: f(x) or f^{(n)}(x), f(x, y) or f^{(n)}(x, y), and the same with the first argument as a subscript, f_x(y) or f_x(y, z).

Notation for functions with a fixed LaTeX form, such as |x|, \lfloor x \rfloor, \binom{n}{k} or \overline{z} (the simple2 variants for two-argument functions such as binomial coefficients, small writing the arguments in small style), and a few special functions with unusual notation.

Logical connectives and quantifiers (Not, And, Or, Implies, All, Exists, ...), extrema and similar operators over sets (Maximum, Minimum, Infimum, ArgMax, Poles, ...), collections (List, Tuple, Set, also in set-builder form), integer ranges, matrices, and piecewise definitions (Cases).

Algebraic structures such as polynomial and power series rings R[x], R[[x]]; Where expressions with local definitions; ShowExpandedNormalForm; and Decimal literals.

Cite this page

The FLINT team, “fexpr.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fexpr/index.html (generated 2026-10-20).