# Miscellaneous Functions

There are various other functions in CYTools that don't belong to any particular class. They are defined in different places according to where they most closely belong. Here we list the location of the definitions of these functions as well as their documentation.

## Functions in `cytools.triangulation`

`_cgal_triangulate`

**Description:**
Computes a regular triangulation using CGAL.

This function is not intended to be called by the end user. Instead, it is
used by the `Triangulation`

class when using CGAL as the
backend.

**Arguments:**

`points`

: A list of points.`heights`

: A list of heights defining the regular triangulation.

**Returns:**
A list of simplices defining a regular triangulation.

**Example**

This function is not intended to be directly used, but it is used in the following example. We construct a triangulation using CGAL.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-6,-9]])`

p.triangulate(backend="cgal")

# A fine, star triangulation of a 4-dimensional point configuration with 7

# points in ZZ^4

`_qhull_triangulate`

**Description:**
Computes a regular triangulation using QHull.

This function is not intended to be called by the end user. Instead, it is
used by the `Triangulation`

class when using QHull as
the backend.

**Arguments:**

`points`

: A list of points.`heights`

: A list of heights defining the regular triangulation.

**Returns:**
A list of simplices defining a regular triangulation.

**Example**

This function is not intended to be directly used, but it is used in the following example. We construct a triangulation using QHull.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-6,-9]])`

p.triangulate(backend="qhull")

# A fine, star triangulation of a 4-dimensional point configuration with 7

# points in ZZ^4

`_to_star`

**Description:**
Turns a triangulation into a star triangulation by deleting internal lines
and connecting all points to the origin.

This function is not intended to be called by the end user. Instead, it is
used by the `Triangulation`

class when needed.

This function is only reliable for triangulations of reflexive polytopes and may produce invalid triangulations for other polytopes.

**Arguments:**

`simplices`

: The list of simplices of the triangulation. Each simplex consists of the list of indices of the points forming its vertices.`facets`

: The list of facets of the polytope. Each facet consists of the indices of the points in the facet.`star_origin`

: The index of the point that is used as the star origin.

**Returns:**
A list of simplices forming a star triangulation.

**Example**

This function is not intended to be directly used, but it is used in the following example. We input a triangulation that is not star and ask it to turn it into a star triangulation.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-6,-9]])`

p.triangulate(simplices=[[1,2,3,4,6],[1,2,3,5,6],[2,3,4,5,6]]) # The input triangulation is not star

# A non-fine, regular, non-star triangulation of a 4-dimensional point configuration with 7 points in ZZ^4

p.triangulate(simplices=[[1,2,3,4,6],[1,2,3,5,6],[2,3,4,5,6]], make_star=True) # We can turn it into a star triangulation

# A fine, regular, star triangulation of a 4-dimensional point configuration with 7 points in ZZ^4

`_topcom_triangulate`

**Description:**
Computes the placing/pushing triangulation using TOPCOM.

This function is not intended to be called by the end user. Instead, it is
used by the `Triangulation`

class when using TOPCOM as
the backend.

**Arguments:**

`points`

: A list of points.

**Returns:**
A list of simplices defining a triangulation.

**Example**

This function is not intended to be directly used, but it is used in the following example. We construct a triangulation using TOMCOM.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-6,-9]])`

p.triangulate(backend="topcom")

# A fine, star triangulation of a 4-dimensional point configuration with 7

# points in ZZ^4

`all_triangulations`

**Description:**
Computes all triangulations of the input point configuration using TOPCOM.
There is the option to only compute fine, regular or fine triangulations.

This function is not intended to be called by the end user. Instead, it is
used by the `all_triangulations`

function
of the `Polytope`

class.

**Arguments:**

`points`

: The list of points to be triangulated.`only_fine`

: Restricts to only fine triangulations.`only_regular`

: Restricts to only regular triangulations.`only_star`

: Restricts to only star triangulations.`star_origin`

: The index of the point that will be used as the star origin. If the polytope is reflexive this is set to 0, but otherwise it must be specified.`backend`

: The optimizer used to check regularity computation. The available options are "topcom" and the backends of the`is_solid`

function of the`Cone`

class. If not specified, it will be picked automatically. Note that using TOPCOM to check regularity is slower.`poly`

: The ambient polytope. It is constructed if not specified.`raw_output`

: Return the triangulations as lists of simplices instead of as Triangulation objects.

**Returns:**
A generator of `Triangulation`

objects with the
specified properties. If `raw_output`

is set to True then numpy arrays are
used instead.

**Example**

This function is not intended to be directly used, but it is used in the following example. We construct a polytope and find all of its triangulations. We try picking different restrictions and see how the number of triangulations changes.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-2,-1,-1],[-2,-1,-1,-1]])`

g = p.all_triangulations()

next(g) # Takes some time while TOPCOM finds all the triangulations

# A fine, regular, star triangulation of a 4-dimensional point

# configuration with 7 points in ZZ^4

next(g) # Produces the next triangulation immediately

# A fine, regular, star triangulation of a 4-dimensional point

# configuration with 7 points in ZZ^4

len(p.all_triangulations(as_list=True)) # Number of fine, regular, star triangulations

# 2

len(p.all_triangulations(only_regular=False, only_star=False, only_fine=False, as_list=True) )# Number of triangularions, no matter if fine, regular, or star

# 6

`random_triangulations_fair_generator`

**Description:**
Constructs pseudorandom regular (optionally star) triangulations of a given
point set. Implements Algorithm #3 from the paper
*Bounding the Kreuzer-Skarke Landscape* by Mehmet Demirtas, Liam
McAllister, and Andres Rios-Tascon.
arXiv:2008.01730

This is a Markov chain Monte Carlo algorithm that involves taking random walks inside the subset of the secondary fan corresponding to fine triangulations and performing random flips. For details, please see Section 4.1 in the paper.

- This function is not intended to be called by the end user. Instead, it
is used by the
`random_triangulations_fair`

function of the`Polytope`

class. - This function is designed mainly for large polytopes where sampling triangulations is challenging. When small polytopes are used it is likely to get stuck.

**Arguments:**

`triang_pts`

: The list of points to be triangulated.`N`

: Number of desired unique triangulations. If not specified, it will generate as many triangulations as it can find until it has to retry more than max_retries times to obtain a new triangulation.`n_walk`

: Number of hit-and-run steps per triangulation.`n_flip`

: Number of random flips performed per triangulation.`initial_walk_steps`

: Number of hit-and-run steps to take before starting to record triangulations. Small values may result in a bias towards Delaunay-like triangulations.`walk_step_size`

: Determines size of random steps taken in the secondary fan. Algorithm may stall if too small.`max_steps_to_wall`

: Maximum number of steps to take towards a wall of the subset of the secondary fan that correspond to fine triangulations. If a wall is not found, a new random direction is selected. Setting this to be very large (>100) reduces performance. If this, or walk_step_size, is set to be too low, the algorithm may stall.`fine_tune_steps`

: Number of steps to determine the location of a wall. Decreasing improves performance, but might result in biased samples.`max_retries`

: Maximum number of attempts to obtain a new triangulation before the process is terminated.`make_star`

: Converts the obtained triangulations into star triangulations.`backend`

: Specifies the backend used to compute the triangulation. The available options are "cgal" and "qhull".`poly`

: The ambient polytope. It is constructed if not specified.`seed`

: A seed for the random number generator. This can be used to obtain reproducible results.

**Returns:**
A generator of `Triangulation`

objects with the
specified properties.

**Example**

This function is not intended to be directly used, but it is used in the
following example. We construct a polytope and find some random
triangulations. The computation takes considerable time, but they should be
a fair sample from the full set of triangulations (if the parameters are
chosen correctly). For (some) machine learning purposes or when the
fairness of the sample is not crucial, the
`random_triangulations_fast`

function should be used instead.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]]).dual()`

g = p.random_triangulations_fast()

next(g) # Takes a long time (around a minute)

# A fine, regular, star triangulation of a 4-dimensional point configuration with 106 points in ZZ^4

next(g) # Takes slightly shorter (still around a minute)

# A fine, regular, star triangulation of a 4-dimensional point

# configuration with 106 points in ZZ^4

rand_triangs = p.random_triangulations_fair(N=10, as_list=True) # Produces the list of 10 triangulations, but takes a long time (around 10 minutes)

It is worth noting that the time it takes to obtain each triangulation varies very significantly on the parameters used. The function tries to guess reasonable parameters, but it is better to adjust them to your desired balance between speed and fairness of the sampling.

`random_triangulations_fast_generator`

Constructs pseudorandom regular (optionally fine and star) triangulations of a given point set. This is done by picking random heights around the Delaunay heights from a Gaussian distribution.

This function is not intended to be called by the end user. Instead, it is
used by the
`random_triangulations_fast`

function of the `Polytope`

class.

This function produces random triangulations very quickly, but it does not
produce a fair sample. When a fair sampling is required the
`random_triangulations_fair`

function should be used.

**Arguments:**

`triang_pts`

: The list of points to be triangulated.`N`

: Number of desired unique triangulations. If not specified, it will generate as many triangulations as it can find until it has to retry more than max_retries times to obtain a new triangulation.`c`

: A contant used as the standard deviation of the Gaussian distribution used to pick the heights. A larger c results in a wider range of possible triangulations, but with a larger fraction of them being non-fine, which slows down the process when using only_fine=True.`max_retries`

: Maximum number of attempts to obtain a new triangulation before the process is terminated.`make_star`

: Converts the obtained triangulations into star triangulations.`only_fine`

: Restricts to fine triangulations.`backend`

: Specifies the backend used to compute the triangulation. The available options are "cgal" and "qhull".`poly`

: The ambient polytope. It is constructed if not specified.`seed`

: A seed for the random number generator. This can be used to obtain reproducible results.

**Returns:**
A generator of `Triangulation`

objects with the
specified properties.

**Example**

This function is not intended to be directly used, but it is used in the
following example. We construct a polytope and find some random
triangulations. The triangulations are obtained very quicly, but they are
not a fair sample of the space of triangulations. For a fair sample, the
`random_triangulations_fair`

function should be used.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]]).dual()`

g = p.random_triangulations_fast()

next(g) # Runs very quickly

# A fine, regular, star triangulation of a 4-dimensional point

# configuration with 106 points in ZZ^4

next(g) # Keeps producing triangulations until it has trouble finding more

# A fine, regular, star triangulation of a 4-dimensional point

# configuration with 106 points in ZZ^4

rand_triangs = p.random_triangulations_fast(N=10, as_list=True) # Produces the list of 10 triangulations very quickly

## Functions in `cytools.cone`

`is_extremal`

**Description:**
Auxiliary function that is used to find the extremal rays of cones. Returns
True if the ray is extremal and False otherwise. It has additional
parameters that are used when parallelizing.

**Arguments:**

`A`

*(array_like)*: A matrix where the columns are rays (excluding b).`b`

*(array_like)*: The vector that will be checked if it can be expressed as a positive linear combination of the columns of A.`i`

*(int, optional)*: An id number that is used when parallelizing.`q`

*(multiprocessing.Queue, optional)*: A queue that is used when parallelizing.`tol`

*(float, optional, default=1e-4)*: The tolerance for determining whether a ray is extremal.

**Returns:**
*(bool or None)* The truth value of the ray being extremal. If the process
fails then it returns nothing.

**Example**

This function is not meant to be directly used by the end user. Instead it
is used by the `extremal_rays`

function. We construct a
cone and find its extremal_rays.

`c = Cone([[0,1],[1,1],[1,0]])`

c.extremal_rays()

# array([[0, 1],

# [1, 0]])

## Functions in `cytools.utils`

`array_from_flint`

**Description:**
Converts a numpy array with fmpz/fmpq (Flint's integer/float number class)
entries to 64-bit integer/float entries.

**Arguments:**

`arr`

: A numpy array with fmpz/fmpq entries.

**Returns:**
A numpy array with 64-bit integer/float entries.

`array_to_flint`

**Description:**
Converts a numpy array with either:
1) 64-bit integer entries or
2) float entries
to Flint type (fmpz or fmpq for integer or rational numbers, respectively).

See https://flintlib.org/doc/fmpz.html and https://flintlib.org/doc/fmpq.html

**Arguments:**

`arr`

: A numpy array with either 64-bit integer or float entries.

**Returns:**
A numpy array with either fmpz or fmpq entries.

**Example**

We convert an integer array to an fmpz array.

`from cytools.utils import array_int_to_fmpz`

arr = [[1,0,0],[0,2,0],[0,0,3]]

array_int_to_fmpz(arr)

# array([[1, 0, 0],

# [0, 2, 0],

# [0, 0, 3]], dtype=object)

`fetch_polytopes`

**Description:**
Fetches reflexive polytopes from the Kreuzer-Skarke database or from the
Schöller-Skarke database. The data is fetched from the websites
http://hep.itp.tuwien.ac.at/~kreuzer/CY/ and
http://rgc.itp.tuwien.ac.at/fourfolds/ respectively.

The Kreuzer-Skarke database does not store favorability data. Thus, when setting favorable to True or False it fetches additional polytopes so that after filtering by favorability it can saturate the requested limit. However, it may happen that fewer polytopes than requested are returned even though more exist. To verify that no more polytopes with the requested conditions exist one can increase the limit significantly and check if more polytopes are returned.

**Arguments:**

`h11`

: The Hodge number $h^{1,1}$ of the Calabi-Yau hypersurface.`h12`

: The Hodge number $h^{1,2}$ of the Calabi-Yau hypersurface.`h13`

: The Hodge number $h^{1,3}$ of the Calabi-Yau hypersurface.`h21`

: The Hodge number $h^{2,1}$ of the Calabi-Yau hypersurface. This is equivalent to the h12 parameter.`h22`

: The Hodge number $h^{2,2}$ of the Calabi-Yau hypersurface.`h31`

: The Hodge number $h^{3,1}$ of the Calabi-Yau hypersurface. This is equivalent to the h13 parameter.`chi`

: The Euler characteristic of the Calabi-Yau hypersurface.`lattice`

: The lattice on which the polytope is defined. Options are "N" and "M". Has to be specified if the Hodge numbers or the Euler characteristic is specified.`dim`

: The dimension of the polytope. Only available options are 4 and 5.`n_points`

: The number of lattice points of the desired polytopes.`n_vertices`

: The number of vertices of the desired polytopes.`n_dual_points`

: The number of points of the dual polytopes of the desired polytopes.`n_facets`

: The number of facets of the desired polytopes.`limit`

: The maximum number of fetched polytopes.`timeout`

: The maximum number of seconds to wait for the server to return the data.`as_list`

: Return the list of polytopes instead of a generator.`backend`

: A string that specifies the backend used for the`Polytope`

class.`dualize`

: Flag that indicates whether to dualize all the polytopes before yielding them.`favorable`

: Yield or return only polytopes that are favorable when set to True, or non-favorable when set to False. If not specified then it yields both favorable and non-favorable polytopes.

**Returns:**
A generator of `Polytope`

objects, or the full list when
`as_list`

is set to True.

**Example**

We fetch polytopes from the Kreuzer-Skarke and Schöller-Skarke databases with a few different parameters.

`from cytools import fetch_polytopes # Note that it can directly be imported from the root`

g = fetch_polytopes(h11=27, lattice="N") # Constructs a generator of polytopes

next(g)

# A 4-dimensional reflexive lattice polytope in ZZ^4

l = fetch_polytopes(h11=27, lattice="N", as_list=True, limit=100) # Constructs a generator of polytopes

print(f"Fetched {len(l)} polytopes")

# Fetched 100 polytopes

g_5d = fetch_polytopes(h11=1000, lattice="N", dim=5, limit=100) # Generator of 5D polytopes

next(g_5d)

# A 5-dimensional reflexive lattice polytope in ZZ^5

`filter_tensor_indices`

**Description:**
Selects a specific subset of indices from a tensor.

The tensor is reindexed so that indices are in the range 0..len(indices) with the ordering specified by the input indices. This function can be used to convert the tensor of intersection numbers to a given basis.

**Arguments:**

`tensor`

: The input symmetric sparse tensor of the form of a dictionary {(a,b,...,c):M_ab...c, ...}.`indices`

: The list of indices that will be preserved.

**Returns:**
A dictionary describing a tensor in the same format as the input, but only with the desired indices.

**Example**

We construct a simple tensor and then filter some of the indices. We also give a concrete example of when this is used for intersection numbers.

`from cytools.utils import filter_tensor_indices`

tensor = {(0,1):0, (1,1):1, (1,2):2, (1,3):3, (2,3):4}

filter_tensor_indices(tensor, [1,3])

# {(0, 0): 1, (0, 1): 3}

p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-1,-1]])

t = p.triangulate()

v = t.get_toric_variety()

intnums_nobasis = v.intersection_numbers(in_basis=False)

intnums_inbasis = v.intersection_numbers(in_basis=True)

intnums_inbasis == filter_tensor_indices(intnums_nobasis, v.divisor_basis())

# True

`find_new_affinely_independent_points`

**Description:**
Finds new points that are affinely independent to the input list of points.

This is useful when one wants to turn a polytope that is not full-dimensional into one that is, without affecting the structure of the triangulations.

**Arguments:**

`pts`

: A list of points.

**Returns:**
A list of affinely independent points with respect to the ones inputted.

**Example**

We construct a list of points and then find a set of affinely independent points.

`pts = [[1,0,1],[0,0,1],[0,1,1]]`

find_new_affinely_independent_points(pts)

array([[1, 0, 2]])

`float_to_fmpq`

**Description:**
Converts a float to an fmpq (Flint's rational number class).

See https://flintlib.org/doc/fmpq.html

**Arguments:**

`c`

: The input number.

**Returns:**
The rational number that most reasonably approximates the input.

**Example**

We convert a few floats to rational numbers.

`from cytools.utils import float_to_fmpq`

float_to_fmpq(0.1), float_to_fmpq(0.333333333333), float_to_fmpq(2.45)

# (1/10, 1/3, 49/20)

`fmpq_to_float`

**Description:**
Converts an fmpq (Flint's rational number class) to a float.

See https://flintlib.org/doc/fmpq.html

**Arguments:**

`c`

: The input rational number.

**Returns:**
The number as a float.

**Example**

We convert a few rational numbers to floats.

`from cytools.utils import fmpq_to_float`

from flint import fmpq

fmpq_to_float(fmpq(1,2)), fmpq_to_float(fmpq(1,3)),\

fmpq_to_float(fmpq(49,20))

# (0.5, 0.3333333333333333, 2.45)

`gcd_float`

**Description:**
Compute the greatest common (floating-point) divisor of a and b. This is
simply the largest floating point number that divides a and b. Uses the
Euclidean algorithm.

Warning - unexpected/buggy behavior can occur if b starts tiny. E.g., gcd_float(100,0.1,0.2) returns 100.

This only seems to be a risk if b *starts* below tol.

**Arguments:**

`a`

: The first number.`b`

: The second number.`tol`

: The tolerance for rounding.

**Returns:**
The gcd of a and b.

**Example**

We compute the gcd of two floats. This function is useful since the standard gcd functions raise an error for non-integer values.

`from cytools.utils import gcd_float`

gcd_float(0.2, 0.5)

# Should be 0.1, but there are small rounding errors

# 0.09999999999999998

`lll_reduce`

Apply lll-reduction to the input points (the rows).

**Arguments:**

`pts`

: A list of points.

**Returns:**
The reduced points (pts_red; as rows).
The transformation matrix/inverse (A, Ainv) s.t. pts_red.T = A*pts_in.T

`polytope_generator`

**Description:**
Reads polytopes from a file or a string. The polytopes can be specified
with their vertices, as used in the Kreuzer-Skarke database, or from a
weight system.

This function is not intended to be called by the end user. Instead, it is
used by the `read_polytopes`

and
`fetch_polytopes`

functions.

**Arguments:**

`input`

: Specifies the name of the file to read or the string containing the polytopes.`input_type`

: Specifies whether to read from a file or from the input string. Options are "file" or "str".`format`

: Specifies the format to read. The options are "ks", which is the format used in the KS database, and "ws", if the polytopes should be constructed from weight systems.`backend`

: A string that specifies the backend used for the`Polytope`

class.`dualize`

: Flag that indicates whether to dualize all the polytopes before yielding them.`favorable`

: Yield only polytopes that are favorable when set to True, or non-favorable when set to False. If not specified then it yields both favorable and non-favorable polytopes.`lattice`

: The lattice to use when checking favorability. This parameter is only required when`favorable`

is set. Options are "M" and "N".`limit`

: Sets a maximum numbers of polytopes to yield.

**Returns:**
A generator of `Polytope`

objects.

**Example**

Since this function should not be used directly, we show an example of it
being used with the `read_polytopes`

function. We take a
string obtained from the KS database and read the polytope it specifies.

`from cytools import read_polytopes # Note that it can directly be imported from the root`

poly_data = '''4 5 M:10 5 N:376 5 H:272,2 [540]

1 0 0 0 -9

0 1 0 0 -6

0 0 1 0 -1

0 0 0 1 -1

'''

read_polytopes(poly_data, input_type="str", as_list=True)

# [A 4-dimensional reflexive lattice polytope in ZZ^4]

`read_polytopes`

**Description:**
Reads polytopes from a file or a string. The polytopes can be specified
with their vertices, as used in the Kreuzer-Skarke database, or from a
weight system.

**Arguments:**

`input`

: Specifies the name of the file to read or the string containing the polytopes.`input_type`

: Specifies whether to read from a file or from the input string. Options are "file" or "str".`format`

: Specifies the format to read. The options are "ks", which is the format used in the KS database, and "ws", if the polytopes should be constructed from weight systems.`backend`

: A string that specifies the backend used for the`Polytope`

class.`as_list`

: Return the list of polytopes instead of a generator.`dualize`

: Flag that indicates whether to dualize all the polytopes before yielding them.`favorable`

: Yield or return only polytopes that are favorable when set to True, or non-favorable when set to False. If not specified then it yields both favorable and non-favorable polytopes.`lattice`

: The lattice to use when checking favorability. This parameter is only required when`favorable`

is set. Options are "M" and "N".`limit`

: Sets a maximum numbers of polytopes to yield.

**Returns:**
A generator of `Polytope`

objects, or the full list when
`as_list`

is set to True.

**Example**

We take a string obtained from the KS database and read the polytope it specifies.

`from cytools import read_polytopes # Note that it can directly be imported from the root`

poly_data = '''4 5 M:10 5 N:376 5 H:272,2 [540]

1 0 0 0 -9

0 1 0 0 -6

0 0 1 0 -1

0 0 0 1 -1

'''

read_polytopes(poly_data, input_type="str", as_list=True)

# [A 4-dimensional reflexive lattice polytope in ZZ^4]

`set_curve_basis`

**Description:**
Specifies a basis of curves of the toric variety, which in turn specifies a
dual basis of divisors. This can be done with a vector specifying the
indices of the dual prime toric divisors or as a matrix with the rows being
the basis curves, and the entries are the intersection numbers with the
prime toric divisors. Note that when using a vector it is equivalent to
using the same vector in the `set_divisor_basis`

function.

This function should generally not be called directly by the user. Instead,
it is called by the `set_curve_basis`

function of the `ToricVariety`

class, or the
`set_curve_basis`

function of the
`CalabiYau`

class.

Only integral bases are supported by CYTools, meaning that all toric curves must be able to be written as an integral linear combination of the basis curves.

**Arguments:**

`tv_or_cy`

: The toric variety or Calabi-Yau whose basis will be set.`basis`

: Vector or matrix specifying a basis. When a vector is used, the entries will be taken as indices of the standard basis of the dual to the lattice of prime toric divisors. When a matrix is used, the rows are taken as linear combinations of the aforementioned elements.`include_origin`

: Whether to interpret the indexing specified by the input vector as including the origin.

**Returns:**
Nothing.

**Example**

This function is not intended to be directly used, but it is used in the following example. We consider a simple toric variety with two independent curves. We first find the default basis of curves it picks and then set a basis of our choice.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-6,-9]])`

t = p.triangulate()

v = t.get_toric_variety()

v.curve_basis() # We haven't set any basis

# array([1, 6])

v.set_curve_basis([5,6]) # Here we set a basis

v.curve_basis() # We get the basis we set

# array([5, 6])

v.curve_basis(as_matrix=True) # We get the basis in matrix form

# array([[-18, 1, 9, 6, 1, 1, 0],

# [ -6, 0, 3, 2, 0, 0, 1]])

Note that when setting a curve basis in this way, the function behaves
exactly the same as `set_divisor_basis`

. For a more
advanced example involving generic bases these two functions differ. An
example can be found in the experimental features section.

`set_divisor_basis`

**Description:**
Specifies a basis of divisors for the toric variety or Calabi-Yau manifold,
which in turn specifies a dual basis of curves. This can be done with a
vector specifying the indices of the prime toric divisors, or as a matrix
where each row is a linear combination of prime toric divisors.

This function should generally not be called directly by the user. Instead,
it is called by the `set_divisor_basis`

function of the `ToricVariety`

class, or the
`set_divisor_basis`

function of the
`CalabiYau`

class.

Only integral bases are supported by CYTools, meaning that all prime toric divisors must be able to be written as an integral linear combination of the basis divisors.

**Arguments:**

`tv_or_cy`

: The toric variety or Calabi-Yau whose basis will be set.`basis`

: Vector or matrix specifying a basis. When a vector is used, the entries will be taken as the indices of points of the polytope or prime divisors of the toric variety. When a matrix is used, the rows are taken as linear combinations of the aforementioned divisors.`include_origin`

: Whether to interpret the indexing specified by the input vector as including the origin.

**Returns:**
Nothing.

**Example**

This function is not intended to be directly used, but it is used in the following example. We consider a simple toric variety with two independent divisors. We first find the default basis it picks and then we set a basis of our choice.

`p = Polytope([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1],[-1,-1,-6,-9]])`

t = p.triangulate()

v = t.get_toric_variety()

v.divisor_basis() # We haven't set any basis

# array([1, 6])

v.set_divisor_basis([5,6]) # Here we set a basis

v.divisor_basis() # We get the basis we set

# array([5, 6])

v.divisor_basis(as_matrix=True) # We get the basis in matrix form

# array([[0, 0, 0, 0, 0, 1, 0],

# [0, 0, 0, 0, 0, 0, 1]])

An example for more generic basis choices can be found in the experimental features section.

`solve_linear_system`

**Description:**
Solves the sparse linear system M*x + C = 0.

**Arguments:**

`M`

: The matrix.`C`

: The constant term.`backend`

: The solver to use. Options are "all", "sksparse" and "scipy". When set to "all" it tries all available backends.`check`

: Whether to explicitly check the solution to the linear system.`backend_error_tol`

: Error tolerance for the solution.`verbosity`

: The verbosity level.- verbosity = 0: Do not print anything.
- verbosity = 1: Print warnings when backends fail.

**Returns:**
Floating-point solution to the linear system.

**Example**

We solve a very simple linear equation.

`from cytools.utils import to_sparse, solve_linear_system`

id_array = [[0,0,1],[1,1,1],[2,2,1],[3,3,1],[4,4,1]]

M = to_sparse(id_array, sparse_type="csr")

C = [1,1,1,1,1]

solve_linear_system(M, C)

# array([-1., -1., -1., -1., -1.])

`symmetric_dense_to_sparse`

**Description:**
Converts a dense symmetric tensor to a sparse tensor of the form
{(a,b,...,c):M_ab...c, ...}.

The upper triangular indices are used. That is, a<=b<=...<=c.

Optionally, it applies a basis transformation.

**Arguments:**

`tensor`

: A dense symmetric tensor.`basis`

: A matrix where the rows are the basis elements.

**Returns:**
A sparse tensor of the form {(a,b,...,c):M_ab...c, ...}.

**Example**

We construct a simple tensor and then convert it to a dense array. We
consider the same example as for the
`filter_tensor_indices`

function, but now we have
to specify the basis in matrix form.

`from cytools.utils import symmetric_dense_to_sparse`

tensor = [[1,2],[2,3]]

symmetric_dense_to_sparse(tensor)

# {(0, 0): 1, (0, 1): 2, (1, 1): 3}

`symmetric_sparse_to_dense`

**Description:**
Converts a symmetric sparse tensor of the form {(a,b,...,c): M_ab...c, ...}
to a dense tensor.

Optionally, it then applies a basis transformation.

**Arguments:**

`tensor`

: A sparse tensor of the form {(a,b,...,c):M_ab...c, ...}.`basis`

: A matrix where the rows are the basis elements.

**Returns:**
A dense tensor.

**Example**

We construct a simple tensor and then convert it to a dense array. We
consider the same example as for the
`filter_tensor_indices`

function, but now we have
to specify the basis in matrix form.

`from cytools.utils import symmetric_sparse_to_dense_in_basis`

tensor = {(0,1):0, (1,1):1, (1,2):2, (1,3):3, (2,3):4}

basis = [[0,1,0,0],[0,0,0,1]]

symmetric_sparse_to_dense(tensor, basis)

# array([[1, 3],

# [3, 0]])

`to_sparse`

**Description:**
Converts a (manually implemented) sparse matrix of the form
[[a,b,M_ab], ...] or a dictionary of the form {(a,b):M_ab, ...} to a formal
dok_matrix or to a csr_matrix.

**Arguments:**

`arr`

: A list of the form [[a,b,M_ab],...] or a dictionary of the form [(a,b):M_ab,...].`sparse_type`

: The type of sparse matrix to return. The options are "dok" and "csr".

**Returns:**
The sparse matrix in dok_matrix or csr_matrix format.

**Example**

We convert the 5x5 identity matrix into a sparse matrix.

`from cytools.utils import to_sparse`

id_array = [[0,0,1],[1,1,1],[2,2,1],[3,3,1],[4,4,1]]

to_sparse(id_array)

# <5x5 sparse matrix of type '<class 'numpy.float64'>'

# with 5 stored elements in Dictionary Of Keys format>

to_sparse(id_array, sparse_type="csr")

# <5x5 sparse matrix of type '<class 'numpy.float64'>'

# with 5 stored elements in Compressed Sparse Row format>

## Functions in `cytools.config`

`check_mosek_license`

**Description:**
Checks if the Mosek license is valid. If it is not, it prints the reason.

**Arguments:**
None.

**Returns:**
Nothing.

**Example**

The Mosek license should be automatically checked, but it can also be checked as follows.

`import cytools`

cytools.config.check_mosek_license()

# It will print an error if it is not working, and if nothing is printed

# then it is working correctly

`enable_experimental_features`

**Description:**
Enables the experimental features of CYTools. For more information read the
experimental features page.

**Arguments:**
None.

**Returns:**
Nothing.

**Example**

We enable the experimental features.

`import cytools`

cytools.config.enable_experimental_features()

`set_mosek_path`

**Description:**
Sets a custom path to the Mosek license. This is useful if the Docker image
was built without the license, but it is stored somewhere in your computer.
The license will be checked after the new path is set.

**Arguments:**

`path`

*(str)*: The path to the Mosek license. Note that the mounted directory on the Docker container is`/home/cytools/mounted_volume/`

.

**Returns:**
Nothing.

**Example**

We set the path to the original one for illustation purposes, and show how to set the path to a directory on the host computer.

`import cytools`

cytools.config.set_mosek_path("/opt/cytools/external/mosek/mosek.lic") # Original path

cytools.config.set_mosek_path("/home/cytools/mounted_volume/[path-to-license]") # If not in the Docker image

## Functions in `cytools.__init__`

`check_for_updates`

**Description:**
Checks for updates of CYTools. It prints a message if a new version is
avaiable, and displays a warning if the current version has a serious bug.

**Arguments:**
None.

**Returns:**
Nothing.

**Example**

We check for updates of CYTools. This is done automatically, so there is usually no need to do this.

`import cytools`

cytools.check_for_updates()