simsopt._core package

Submodules

simsopt._core.derivative module

class simsopt._core.derivative.Derivative(data={})

Bases: object

This class stores the derivative of a scalar output wrt to the individual Optimizable classes that are required to compute this output.

The idea of this class is as follows:

Consider a situation

inA = OptimA()
inB = OptimB()
inter1 = Intermediate1(inA, inB)
inter2 = Intermediate2(inA, inB)
obj = Objective(inter1, inter2)

Then obj.dJ(partials=True) will return a Derivative object containing a dictionary

{
    inA : dobj/dinA,
    inB : dobj/dinB,
}

with

dobj/dinA = dobj/dinter1 * dinter1/dinA + dobj/dinter2 * dinter2/dinA
dobj/dinB = dobj/dinter1 * dinter1/dinB + dobj/dinter2 * dinter2/dinB

SIMSOPT computes these derivatives by first computing dobj/dinter1 and dobj/dinter2 and then passing this vector to Intermediate1.vjp and Intermediate2.vjp, which returns

{
    inA: dobj/dinter1 * dinter1/dinA
    inB: dobj/dinter1 * dinter1/dinA
}

and

{
    inA: dobj/dinter2 * dinter2/dinA
    inB: dobj/dinter2 * dinter2/dinA
}

respectively. Due to the overloaded __add__ and __iadd__ functions adding the Derivative objects than results in the desired

{
    inA: dobj/dinter1 * dinter1/dinA + dobj/dinter2 * dinter2/dinA
    inB: dobj/dinter1 * dinter1/dinA + dobj/dinter2 * dinter2/dinA
}

This Derivative can then be used to obtain partial derivatives or the full gradient of J, via

dJ = obj.dJ(partials=True)
dJ_by_dinA = dJ(inA) # derivative of Objective w.r.t. to OptimA
dJ_by_dinB = dJ(inB) # derivative of Objective w.r.t. to OptimB
gradJ = dJ(obj) # gradient of Objective

For the common case in which you just want the gradient of obj.J and do not need the individual partial derivatives, the argument partials=True can be omitted in obj.dJ(). In this case, obj.dJ() directly returns the gradient rather than returning the Derivative object, acting as a shorthand for obj.dJ(partials=True)(obj). This behavior is implemented with the decorator derivative_dec.

__call__(optim: simsopt._core.graph_optimizable.Optimizable)

Get the derivative with respect to all DOFs that optim depends on.

class simsopt._core.derivative.OptimizableDefaultDict(d)

Bases: collections.defaultdict

Custom defaultdict that automatically returns a numpy array of zeros of size equal to the number of free dofs when the key wasn’t found.

simsopt._core.derivative.copy_numpy_dict(d)
simsopt._core.derivative.derivative_dec(func)

This decorator is applied to functions of Optimizable objects that return a derivative, typically named dJ(). This allows obj.dJ() to provide a shorthand for the full gradient, equivalent to obj.dJ(partials=True)(obj). If partials=True, the underlying Derivative object will be returned, so partial derivatives can be accessed and combined to assemble gradients.

simsopt._core.dofs module

This module provides the Dofs class.

This module should not depend on anything involving communication (e.g. MPI) or on specific types of optimization problems.

simsopt._core.dofs.get_owners(obj, owners_so_far=[])

Given an object, return a list of objects that own any degrees of freedom, including both the input object and any of its dependendents, if there are any.

simsopt._core.graph_optimizable module

Provides graph based Optimizable class, whose instances can be used to build an optimization problem in a graph like manner.

class simsopt._core.graph_optimizable.DOFs(x: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, names: Optional[Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]] = None, free: Optional[Union[Sequence[bool], nptyping.types._ndarray.NDArray[None, nptyping.types._bool.Bool]]] = None, lower_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, upper_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None)

Bases: object

Defines the (D)egrees (O)f (F)reedom(s) associated with optimization

This class holds data related to the degrees of freedom associated with an Optimizable object. To access the data stored in the DOFs class, use the labels shown shown in the table below.

External name

Internal name

x

_x

free

_free

lower_bounds

_lb

upper_bounds

_ub

names

_names

The class implements the external name column properties in the above table as properties. Additional methods to update bounds, fix/unfix DOFs, etc. are also defined.

__init__(x: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, names: Optional[Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]] = None, free: Optional[Union[Sequence[bool], nptyping.types._ndarray.NDArray[None, nptyping.types._bool.Bool]]] = None, lower_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, upper_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None) None
Parameters
  • x – Numeric values of the DOFs

  • names – Names of the dofs

  • free – Array of boolean values denoting if the DOFs is are free. False values implies the corresponding DOFs are fixed

  • lower_bounds – Lower bounds for the DOFs. Meaningful only if DOF is not fixed. Default is np.NINF

  • upper_bounds – Upper bounds for the DOFs. Meaningful only if DOF is not fixed. Default is np.inf

all_fixed() bool

Checks if all the DOFs are fixed

Returns

True if all DOFs are fixed

all_free() bool

Checks if all DOFs are allowed to be varied

Returns

True if all DOFs are free to changed

any_fixed() bool

Checks for any free DOFs

Returns

True if any fixed DOF is found, else False

any_free() bool

Checks for any free DOFs

Returns

True if any free DOF is found, else False

property bounds: Tuple[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]], Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]]

Returns: (Lower bounds list, Upper bounds list)

fix(key: Union[numbers.Integral, str]) None

Fixes the specified DOF

Parameters

key – Key to identify the DOF

fix_all() None

Fixes all the DOFs

property free_status: Union[Sequence[bool], nptyping.types._ndarray.NDArray[None, nptyping.types._bool.Bool]]
property full_names
property full_x: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Return all x even the fixed ones

Returns

The values of full DOFs without any restrictions

get(key: Union[numbers.Integral, str]) numbers.Real

Get the value of specified DOF. Even fixed DOFs can be obtained with this method

Args: key: Key to identify the DOF :returns: Value of the DOF

is_free(key: Union[numbers.Integral, str]) bool

Get the status of the specified DOF.

Args: key: Key to identify the DOF :returns: Status of the DOF

property lower_bounds: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Lower bounds of the DOFs

Returns

Lower bounds of the DOFs

property names

Returns: string identifiers of the DOFs

property reduced_len: numbers.Integral

The number of free DOFs.

The standard len function returns the full length of DOFs.

Returns

The number of free DOFs

set(key: Union[numbers.Integral, str], val: numbers.Real)

Modify the value of specified DOF. Even fixed DOFs can modified with this method

Args: key: Key to identify the DOF val: Value of the DOF

unfix(key: Union[numbers.Integral, str]) None

Unfixes the specified DOF

Parameters

key – Key to identify the DOF

unfix_all() None

Makes all DOFs variable Caution: Make sure the bounds are well defined

update_bounds(key: Union[numbers.Integral, str], val: Tuple[numbers.Real, numbers.Real]) None

Updates the bounds of the specified DOF to the given value

Parameters
  • key – DOF identifier

  • val – (lower, upper) bounds of the DOF

update_lower_bound(key: Union[numbers.Integral, str], val: numbers.Real) None

Updates the lower bound of the specified DOF to the given value

Parameters
  • key – DOF identifier

  • val – Numeric lower bound of the DOF

update_upper_bound(key: Union[numbers.Integral, str], val: numbers.Real) None

Updates the upper bound of the specified DOF to the given value

Parameters
  • key – DOF identifier

  • val – Numeric upper bound of the DOF

property upper_bounds: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Returns: Upper bounds of the DOFs

property x: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Returns: The values of the free DOFs.

class simsopt._core.graph_optimizable.Optimizable(x0: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, names: Optional[Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]] = None, fixed: Optional[Union[Sequence[bool], nptyping.types._ndarray.NDArray[None, nptyping.types._bool.Bool]]] = None, lower_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, upper_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, external_dof_setter: Optional[Callable[[...], None]] = None, depends_on: Optional[Sequence[simsopt._core.graph_optimizable.Optimizable]] = None, opt_return_fns: Optional[Sequence[Sequence[str]]] = None, funcs_in: Optional[Sequence[Callable[[...], Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]], numbers.Real]]]] = None, **kwargs)

Bases: collections.abc.Callable, collections.abc.Hashable

Experimental callable ABC that provides lego-like optimizable objects that can be used to partition the optimization problem into a graph.

The class provides many features that simplify defining the optimization problem.

  1. Optimizable and its subclasses define the optimization problem. The optimization problem can be thought of as a directed acycling graph (DAG), with each instance of Optimizable being a vertex (node) in the DAG. Each Optimizable object can take other Optimizable objects as inputs and through this container logic, the edges of the DAG are defined.

    Alternatively, the input Optimizable objects can be thought of as parents to the current Optimizable object. In this approach, the last grand-child defines the optimization problem by embodying all the elements of the parents and grand-parents.

    Each call to child instance gets in turn propagated to the parent. In this way, the last child acts as the final optimization problem to be solved. For an example of the final optimization node, refer to simsopt.objectives.least_squares.LeastSquaresProblem

  2. The class automatically partitions degrees of freedoms (DOFs) of the optimization problem to the associated Optimizable nodes. Each DOF defined in a parent gets passed down to the children as a needed DOF for the child. So a DOF needed by parent node can be given as an input to the methods in the child node. Any of the DOFs could be fixed in which case, it should be removed as an argument to the call-back function from the final Optimizable node.

  3. The class implements a callable hook that provides minimal caching. All derived classes have to register methods that return objective function type values. This is done by implementing the following class attribute in the class definition: .. code-block:: python

    return_fn_map = {‘name1’: method1, ‘name2’: method, …}

    The Optimizable class maintains the list of return functions needed by each of the calling Optimizable objects either during child initialization or later using the provided methods. The calling optimizable object could then call the Optimizable object directly using the __call__ hook or could call the individual methods.

    This back and forth propagation of DOFs partitioning and function calls happens dynamically.

  4. The class is hashable and the names of the instances are unique. So instances of Optimizable class can be used as keys.

Note

  1. If the Optimizable object is called using the __call__ hook, make sure to supply the argument child=self

  2. __init__ takes instances of subclasses of Optimizable as input and modifies them to add the current object as a child for input objects. The return fns of the parent object needed by the child could be specified by using opt_return_fns argument

__eq__(other: simsopt._core.graph_optimizable.Optimizable) bool

Checks the equality condition

Parameters

other – Another object of subclass of Optimizable

Returns: True only if both are the same objects.

__init__(x0: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, names: Optional[Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]] = None, fixed: Optional[Union[Sequence[bool], nptyping.types._ndarray.NDArray[None, nptyping.types._bool.Bool]]] = None, lower_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, upper_bounds: Optional[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]] = None, external_dof_setter: Optional[Callable[[...], None]] = None, depends_on: Optional[Sequence[simsopt._core.graph_optimizable.Optimizable]] = None, opt_return_fns: Optional[Sequence[Sequence[str]]] = None, funcs_in: Optional[Sequence[Callable[[...], Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]], numbers.Real]]]] = None, **kwargs)
Parameters
  • x0 – Initial state (or initial values of DOFs)

  • names – Human identifiable names for the DOFs

  • fixed – Array describing whether the DOFs are free or fixed

  • lower_bounds – Lower bounds for the DOFs

  • upper_bounds – Upper bounds for the DOFs

  • external_dof_setter – Function used by derivative classes to handle DOFs outside of the _dofs object. Mainly used when the DOFs are primarily handled by C++ code. In that case, for all intents and purposes, the _dofs is a duplication of the DOFs stored elsewhere. In such cases, _dofs is used to handle the dof partitioning, but external dofs are used for computation of the objective function.

  • depends_on – Sequence of Optimizable objects on which the current Optimizable object depends on to define the optimization problem in conjuction with the DOFs. If the optimizable problem can be thought of as a direct acyclic graph based on dependencies, the optimizable objects supplied with depends_on act as parent nodes to the current Optimizable object in such an optimization graph

  • opt_return_fns – Specifies the return value for each of the Optimizable object. Used in the case, where Optimizable object can return different return values. Typically return values are computed by different functions defined in the Optimizable object. The return values are selected by choosing the functions. To know the various return values, use the Optimizable.get_return_fn_names function. If the list is empty, default return value is used. If the Optimizable object can return multiple values, the default is the array of all possible return values.

  • funcs_in – Instead of specifying depends_on and opt_return_fns, specify the methods of the Optimizable objects directly. The parent objects are identified automatically. Doesn’t work with funcs_in with a property decorator

_abc_impl = <_abc_data object>
_add_child(child: simsopt._core.graph_optimizable.Optimizable) None

Adds another Optimizable object as child. All the required processing of the dependencies is done in the child node. This method is used mainly to maintain 2-way link between parent and child.

Parameters

child – Direct dependent (child) of the Optimizable object

_get_ancestors() list[Optimizable]

Get all the ancestors of the current Optimizable object

Returns

List of Optimizable objects that are parents of current Optimizable objects

_ids = count(1)
_remove_child(other: simsopt._core.graph_optimizable.Optimizable) None

Remove the specific Optimizable object from the children list.

Parameters

child – Direct dependent (child) of the Optimizable object

_set_local_x(x: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]) None
_set_new_x(parent=None)
_update_free_dof_size_indices() None

Updates the DOFs lengths for the Optimizable object as well as those of the descendent (dependent) Optimizable objects.

Call this function whenever DOFs are fixed or unfixed or when parents are added/deleted. Recursively calls the same function in children

_update_full_dof_size_indices() None

Updates the full DOFs lengths for this instance and those of the children.

Call this function whenever parents are added or removed. Recursively calls the same function in children.

add_parent(index: int, other: simsopt._core.graph_optimizable.Optimizable) None

Adds another Optimizable object as parent at specified index.

Parameters
  • int – Index of the parent’s list

  • other – Another Optimizable object to be added as parent

add_return_fn(child: simsopt._core.graph_optimizable.Optimizable, fn: Union[str, Callable]) None

Add return function to the list of the return functions called by the child Optimizable object

Parameters
  • child – an Optimizable object that is direct dependent of the current Optimizable instance

  • fn – method of the Optimizable object needed by the child

append_parent(other: simsopt._core.graph_optimizable.Optimizable) None

Appends another Optimizable object to parents list

Parameters

other – New parent Optimizable object

property bounds: Tuple[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]], Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]]

Lower and upper bounds of the free DOFs associated with the current Optimizable object and those of its ancestors

property dof_names: Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]

Names (Identifiers) of the DOFs associated with the current Optimizable object and those of its ancestors

property dof_size: numbers.Integral

Total number of free DOFs associated with the Optimizable object as well as parent Optimizable objects.

property dofs_free_status: Union[Sequence[bool], nptyping.types._ndarray.NDArray[None, nptyping.types._bool.Bool]]

Boolean array denoting whether the DOFs associated with the current and ancestors Optimizable objects are free or not

fix(key: Union[numbers.Integral, str]) None

Set the fixed attribute for the given degree of freedom.

Parameters

key – DOF identifier

fix_all() None

Set the ‘fixed’ attribute for all degrees of freedom associated with the current Optimizable object.

property full_dof_names: Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]

Names (Identifiers) of the DOFs associated with the current Optimizable object and those of its ancestors

property full_dof_size: numbers.Integral

Total number of all (free and fixed) DOFs associated with the Optimizable object as well as parent Optimizable objects.

property full_x: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Numeric values of all the DOFs (both free and fixed) associated with the current Optimizable object and those of its ancestors

get(key: Union[numbers.Integral, str]) numbers.Real

Get the value of specified DOF Even fixed dofs can be obtained individually.

Parameters

key – DOF identifier

get_parent_return_fns_list() List[List[Callable]]

Get a list of the funcs returned by the parents as list of lists

Returns

The funcs returned by all the parents of the Optimizable object

get_return_fn_list() List[List[Callable]]

Gets return functions from this Optimizable object used by all the child Optimizable objects

Returns

List of methods that return a value when the current Optimizable object is called from the children.

get_return_fn_names() List[str]

Return the names of the functions that could be used as objective functions.

Returns

List of function names that could be used as objective functions

get_return_fns(child: simsopt._core.graph_optimizable.Optimizable) List[Callable]

Gets return functions from this Optimizable object used by the child Optimizable object

Parameters

child – Dependent Optimizable object

Returns

List of methods that return a value when the current Optimizable object is called from the child

is_fixed(key: Union[numbers.Integral, str]) bool

Checks if the specified dof is fixed

Parameters

key – DOF identifier

is_free(key: Union[numbers.Integral, str]) bool

Checks if the specified dof is free

Parameters

key – DOF identifier

property local_bounds: Tuple[Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]], Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]]

Lower and upper bounds of the free DOFs associated with this Optimizable object

property local_dof_names: Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]

Names (Identifiers) of the DOFs associated with this Optimizable object

property local_dof_size: numbers.Integral

Number of free DOFs associated with the Optimizable object.

Returns

Number of free DOFs associated with the Optimizable object.

property local_dofs_free_status: Union[Sequence[bool], nptyping.types._ndarray.NDArray[None, nptyping.types._bool.Bool]]

Boolean array denoting whether the DOFs associated with the current Optimizable object are free or not

property local_full_dof_names: Union[Sequence[str], nptyping.types._ndarray.NDArray[None, nptyping.types._unicode.Unicode]]

Names (Identifiers) of the DOFs associated with this Optimizable object

property local_full_dof_size: numbers.Integral

Number of all (free and fixed) DOFs associated with the Optimizable object.

Returns

Total number of free and fixed DOFs associated with the Optimizable object.

property local_full_x

Numeric values of all DOFs (both free and fixed) associated with this Optimizable object

property local_lower_bounds: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Lower bounds of the free DOFs associated with this Optimizable object

property local_upper_bounds: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Upper bounds of the free DOFs associated with this Optimizable object

property local_x: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Numeric values of the free DOFs associated with this Optimizable object

property lower_bounds: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Lower bounds of the free DOFs associated with the current Optimizable object and those of its ancestors

property parent_return_fns_no: int

Compute the total number of the return funcs of all the parents of the Optimizable object

Returns

The total number of the return funcs of the Optimizable object’s parents.

pop_parent(index: int = - 1) simsopt._core.graph_optimizable.Optimizable

Removes the parent Optimizable object at specified index.

Parameters

index – Index of the list of the parents

Returns

The removed parent Optimizable object

recompute_bell(parent=None)

Function to be called whenever new DOFs input is given or if the parent Optimizable’s data changed, so the output from the current Optimizable object is invalid.

This method gets called by various DOF setters. If only the local DOFs of an object are being set, the recompute_bell method is called in that object and also in the descendent objects that have a dependency on the object, whose local DOFs are being changed. If gloabl DOFs of an object are being set, the recompute_bell method is called in the object, ancestors of the object, as well as the descendents of the object.

Need to be implemented by classes that provide a dof_setter for external handling of DOFs.

remove_parent(other: simsopt._core.graph_optimizable.Optimizable)

Removes the specified Optimizable object from the list of parents.

Parameters

other – The Optimizable object to be removed from the list of parents

return_fn_map: Dict[str, Callable] = NotImplemented
set(key: Union[numbers.Integral, str], new_val: numbers.Real) None

Update the value held the specified DOF. Even fixed dofs can be set this way

Parameters
  • key – DOF identifier

  • new_val – New value of the DOF

unfix(key: Union[numbers.Integral, str]) None

Unset the fixed attribute for the given degree of freedom

Parameters

key – DOF identifier

unfix_all() None

Unset the ‘fixed’ attribute for all degrees of freedom associated with the current Optimizable object.

property upper_bounds: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Upper bounds of the free DOFs associated with the current Optimizable object and those of its ancestors

property x: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Numeric values of the free DOFs associated with the current Optimizable object and those of its ancestors

simsopt._core.graph_optimizable.make_optimizable(func, *args, dof_indicators=None, **kwargs)

Factory function to generate an Optimizable instance from a function to be used with the graph framework.

Parameters
  • func – Callable to be used in the optimization

  • args – Positional arguments to pass to “func”.

  • dof_indicators – List of strings that match with the length of the args and kwargs. Each string can be either of “opt” - to indicate the argument is optimizable object “dof” - argument that is a degree of freedom for optimization “non-dof” - argument that is not part of optimization. Here ordered property of the dict is used to map kwargs to dof_indicators. Another important thing to consider is dofs related to optimizable objects supplied as arguments should not be given.

  • kwargs – Keyword arguments to pass to “func”.

Returns: Optimizable object to be used in the graph based optimization.

if obj is the returned object, pass obj.J to the LeastSquaresProblem

simsopt._core.optimizable module

This module provides classes and functions that are useful for setting up optimizable objects and objective functions.

class simsopt._core.optimizable.Optimizable

Bases: object

This base class provides some useful features for optimizable functions.

all_fixed(fixed_new=True)

Set the ‘fixed’ attribute for all degrees of freedom.

get(dof_str)

Return a degree of freedom specified by its string name.

get_dofs()

This base Optimizable object has no degrees of freedom, so return an empty array

get_fixed(dof_str)

Return the fixed attribute for a given degree of freedon, specified by dof_str.

index(dof_str)

Given a string dof_str, returns the index in the dof array whose name matches dof_str. If dof_str does not match any of the names, ValueError will be raised.

set(dof_str, newval)

Set a degree of freedom specified by its string name.

set_dofs(x)

This base Optimizable object has no degrees of freedom, so do nothing.

set_fixed(dof_str, fixed_new=True)

Set the fixed attribute for a given degree of freedom, specified by dof_str.

class simsopt._core.optimizable.Target(obj, attr)

Bases: simsopt._core.optimizable.Optimizable

Given an attribute of an object, which typically would be a @property, form a callable function that can be used as a target for optimization.

J()
get_dofs()

This base Optimizable object has no degrees of freedom, so return an empty array

set_dofs(v)

This base Optimizable object has no degrees of freedom, so do nothing.

simsopt._core.optimizable.function_from_user(target)

Given a user-supplied “target” to be optimized, extract the associated callable function.

simsopt._core.optimizable.make_optimizable(obj)

Given any object, add attributes like fixed, mins, and maxs. fixed = False by default. Also, add the other methods of Optimizable to the object.

simsopt._core.util module

This module contains small utility functions and classes needed by _core subpackage.

exception simsopt._core.util.DofLengthMismatchError(input_dof_length: numbers.Integral, optim_dof_length: numbers.Integral, message: Optional[str] = None)

Bases: Exception

Exception raised for errors where the length of supplied DOFs does not match with the length of free DOFs. Especially useful to prevent fully fixed DOFs from not raising Error and to prevent broadcasting of a single DOF

class simsopt._core.util.ImmutableId(id: numbers.Integral)

Bases: object

Immutable class with a single attribute id to represent instance ids. Used in conjuction with InstanceCounterMeta metaclass to generate immutable instance ids starting with 1 for each of the different classes sublcassing InstanceCounterMeta

id: numbers.Integral
class simsopt._core.util.InstanceCounterMeta(name, bases, attrs)

Bases: type

Metaclass to make instance counter not share count with descendants

Ref: https://stackoverflow.com/questions/8628123/counting-instances-of-a-class Credits: https://stackoverflow.com/users/3246302/ratiotile

exception simsopt._core.util.ObjectiveFailure

Bases: Exception

Defines a custom exception used to indicate failure when evaluating the objective function. For example, if Vmec or Spec fail to converge, this exception will be thrown. The simsopt solvers will catch this specific exception (not others) and set the objective function to a large number.

class simsopt._core.util.OptimizableMeta(name, bases, namespace, **kwargs)

Bases: simsopt._core.util.InstanceCounterMeta, abc.ABCMeta, pybind11_builtins.pybind11_type

Meta class for Optimizable class that works with pybind11. Here type(simsoptpp.Curve) is used to obtain the pybind11_type, which can be a parent class from py37

class simsopt._core.util.RegisterMeta(name, bases, attrs)

Bases: type

RegisterMeta class can be used to register functions with easy to identify names.

Note

The class is not used anymore, but kept to explore the idea 3 explained below

The functionality of RegisterMeta is explained with the Spec class defined in simsopt.mhd.spec module. Spec class, which is a subclass of Optimizable, implements two functions volume and iota, which are used by child Optimizables nodes.

One could register the two functions of Spec class in a couple of ways.

  1. Spec.return_fn_map = {'volume': Spec.volume, 'iota': Spec.iota}
    
  2. Spec.volume = Spec.register_return_fn("volume")(Spec.volume)
    Spec.iota = Spec.register_return_fn("iota")(Spec.iota)
    
  3. TO BE IMPLEMENTED

    class Spec
        ...
    
        @register_return_fn("volume")
        def volume(self, ...):
            ...
    
        @register_return_fn("iota")
        def iota(self, ...):
            ...
    
class simsopt._core.util.Struct

Bases: object

This class is just a dummy mutable object to which we can add attributes.

class simsopt._core.util.WeakKeyDefaultDict(default_factory=None, *args, **kwargs)

Bases: weakref.WeakKeyDictionary

A simple implementation of defaultdict that uses WeakKeyDictionary as its parent class instead of standard dictionary.

_abc_impl = <_abc_data object>
simsopt._core.util.finite_difference_steps(x: Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]], abs_step: numbers.Real = 1e-07, rel_step: numbers.Real = 0.0) Union[Sequence[numbers.Real], nptyping.types._ndarray.NDArray[None, nptyping.types._number.Float[float, numpy.floating]]]

Determine an array of step sizes for calculating finite-difference derivatives, using absolute or relative step sizes, or a mixture thereof.

For each element x_j of the state vector x, the step size s_j is determined from

s_j = max(abs(x_j) * rel_step, abs_step)

So, if you want to use the same absolute step size for all elements of x, set rel_step = 0 and set abs_step positive. Or, if you want to use the same relative step size for all elements of x, set abs_step = 0 and rel_step positive. If both abs_step and rel_step are positive, then abs_step effectively gives the lower bound on the step size.

It is dangerous to set abs_step to exactly 0, since then if any elements of x are 0, the step size will be 0. In this situation, ValueError will be raised. It is preferable for abs_step to be a small positive value.

For one-sided finite differences, the values of x_j used will be x_j + s_j. For centered finite differences, the values of x_j used will be x_j + s_j and x_j - s_j.

This routine is used by simsopt._core.dofs.fd_jac() and simsopt.solve.mpi.fd_jac_mpi().

Parameters
  • x – The state vector at which you wish to compute the gradient or Jacobian. Must be a 1D array.

  • abs_step – The absolute step size.

  • rel_step – The relative step size.

Returns

A 1D numpy array of the same size as x, with each element being the step size used for each corresponding element of x.

simsopt._core.util.isbool(val)

Test whether val is any boolean type, either the native python bool or numpy’s bool_.

simsopt._core.util.isnumber(val)

Test whether val is any kind of number, including both native python types or numpy types.

simsopt._core.util.nested_lists_to_array(ll)

Convert a ragged list of lists to a 2D numpy array. Any entries that are None are replaced by 0. This routine is useful for parsing fortran namelists that include 2D arrays using f90nml.

Parameters

ll – A list of lists to convert.

simsopt._core.util.unique(inlist)

Given a list or tuple, return a list in which all duplicate entries have been removed. Unlike a python set, the order of entries in the original list will be preserved. There is surely a faster algorithm than the one used here, but this function will not be used in performance-critical code.

Module contents