pygsti.optimize

pyGSTi Optimization Python Package

Submodules

Package Contents

Classes

ArraysInterface

An interface between pyGSTi's optimization methods and data storage arrays.

UndistributedArraysInterface

An arrays interface for the case when the arrays are not actually distributed.

DistributedArraysInterface

An arrays interface where the arrays are distributed according to a distributed layout.

_VerbosityPrinter

Class responsible for logging things to stdout or a file.

_ResourceAllocation

Describes available resources and how they should be allocated.

_NicelySerializable

The base class for all "nicely serializable" objects in pyGSTi.

OptimizerResult

The result from an optimization.

Optimizer

An optimizer. Optimizes an objective function.

CustomLMOptimizer

A Levenberg-Marquardt optimizer customized for GST-like problems.

_UndistributedArraysInterface

An arrays interface for the case when the arrays are not actually distributed.

_VerbosityPrinter

Class responsible for logging things to stdout or a file.

Functions

_custom_solve(a, b, x, ari, resource_alloc, proc_threshold=100)

Simple parallel Gaussian Elimination with pivoting.

custom_leastsq(obj_fn, jac_fn, x0, f_norm2_tol=1e-06, jac_norm_tol=1e-06, rel_ftol=1e-06, rel_xtol=1e-06, max_iter=100, num_fd_iters=0, max_dx_scale=1.0, damping_mode='identity', damping_basis='diagonal_values', damping_clip=None, use_acceleration=False, uphill_step_threshold=0.0, init_munu='auto', oob_check_interval=0, oob_action='reject', oob_check_mode=0, resource_alloc=None, arrays_interface=None, serial_solve_proc_threshold=100, x_limits=None, verbosity=0, profiler=None)

An implementation of the Levenberg-Marquardt least-squares optimization algorithm customized for use within pyGSTi.

_hack_dx(obj_fn, x, dx, jac, jtj, jtf, f, norm_f)

custom_solve(a, b, x, ari, resource_alloc, proc_threshold=100)

Simple parallel Gaussian Elimination with pivoting.

_find_pivot(a, b, icol, potential_pivot_inds, my_row_slice, shared_floats, shared_ints, resource_alloc, comm, host_comm, buf1, buf2, buf3, best_host_indices, best_host_vals)

_broadcast_pivot_row(a, b, ibest_local, h, k, shared_rowb, local_pivot_rowb, potential_pivot_mask, resource_alloc, comm, host_comm)

_update_rows(a, b, icol, ipivot_local, pivot_row, pivot_b)

_back_substitution(a, b, x, pivot_row_indices, my_row_slice, ari, resource_alloc, host_comm)

_tallskinny_custom_solve(a, b, resource_alloc)

fmax_cg(f, x0, maxiters=100, tol=1e-08, dfdx_and_bdflag=None, xopt=None)

Custom conjugate-gradient (CG) routine for maximizing a function.

minimize(fn, x0, method='cg', callback=None, tol=1e-10, maxiter=1000000, maxfev=None, stopval=None, jac=None, verbosity=0, **addl_kwargs)

Minimizes the function fn starting at x0.

_fmin_supersimplex(fn, x0, abs_outer_tol, rel_outer_tol, inner_tol, max_outer_iter, min_inner_maxiter, max_inner_maxiter, callback, printer)

Minimize a function using repeated applications of the simplex algorithm.

_fmin_simplex(fn, x0, slide=1.0, tol=1e-08, maxiter=1000)

Minimizes a function using a custom simplex implmentation.

_fmin_particle_swarm(f, x0, err_crit, iter_max, printer, popsize=100, c1=2, c2=2)

A simple implementation of the Particle Swarm Optimization Algorithm.

_fmin_evolutionary(f, x0, num_generations, num_individuals, printer)

Minimize a function using an evolutionary algorithm.

create_objfn_printer(obj_func, start_time=None)

Create a callback function that prints the value of an objective function.

_fwd_diff_jacobian(f, x0, eps=1e-10)

check_jac(f, x0, jac_to_check, eps=1e-10, tol=1e-06, err_type='rel', verbosity=1)

Checks a jacobian function using finite differences.

_update_circuit_probs(probs, freqs, circuit_budget)

_minimize(fn, x0, method='cg', callback=None, tol=1e-10, maxiter=1000000, maxfev=None, stopval=None, jac=None, verbosity=0, **addl_kwargs)

Minimizes the function fn starting at x0.

optimize_wildcard_budget_neldermead(budget, L1weights, wildcard_objfn, two_dlogl_threshold, redbox_threshold, printer, smart_init=True, max_outer_iters=10, initial_eta=10.0)

Uses repeated Nelder-Mead to optimize the wildcard budget.

optimize_wildcard_budget_percircuit_only_cvxpy(budget, L1weights, objfn, redbox_threshold, printer)

Uses CVXPY to optimize the wildcard budget. Includes only per-circuit constraints.

_get_critical_circuit_budgets(objfn, redbox_threshold)

_agg_dlogl(current_probs, objfn, two_dlogl_threshold)

_agg_dlogl_deriv(current_probs, objfn, percircuit_budget_deriv, probs_deriv_wrt_percircuit_budget)

_agg_dlogl_hessian(current_probs, objfn, percircuit_budget_deriv, probs_deriv_wrt_percircuit_budget)

_proxy_agg_dlogl(x, tvds, fn0s, percircuit_budget_deriv, two_dlogl_threshold)

_proxy_agg_dlogl_deriv(x, tvds, fn0s, percircuit_budget_deriv)

_proxy_agg_dlogl_hessian(x, tvds, fn0s, percircuit_budget_deriv)

optimize_wildcard_budget_cvxopt(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, abs_tol=1e-05, rel_tol=1e-05, max_iters=50)

Uses CVXOPT to optimize the wildcard budget. Includes both aggregate and per-circuit constraints.

optimize_wildcard_budget_cvxopt_zeroreg(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, abs_tol=1e-05, rel_tol=1e-05, max_iters=50, small=1e-06)

Adds regularization of the L1 term around zero values of the budget. This doesn't seem to help much.

optimize_wildcard_budget_barrier(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, tol=1e-07, max_iters=50, num_steps=3, save_debugplot_data=False)

Uses a barrier method (for convex optimization) to optimize the wildcard budget.

NewtonSolve(initial_x, fn, fn_with_derivs=None, dx_tol=1e-06, max_iters=20, printer=None, lmbda=0.0)

optimize_wildcard_budget_cvxopt_smoothed(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, abs_tol=1e-05, rel_tol=1e-05, max_iters=50)

Uses a smooted version of the objective function. Doesn't seem to help much.

_compute_fd(x, fn, compute_hessian=True, eps=1e-07)

Attributes

_MACH_PRECISION

_fastcalc

class pygsti.optimize.ArraysInterface

Bases: object

An interface between pyGSTi’s optimization methods and data storage arrays.

This class provides an abstract interface to algorithms (particularly the Levenberg-Marquardt nonlinear least-squares algorithm) for creating an manipulating potentially distributed data arrays with types such as “jtj” (Jacobian^T * Jacobian), “jtf” (Jacobian^T * objectivefn_vector), and “x” (model parameter vector). The class encapsulates all the operations on these arrays so that the algorithm doesn’t need to worry about how the arrays are actually stored in memory, e.g. whether shared memory is used or not.

class pygsti.optimize.UndistributedArraysInterface(num_global_elements, num_global_params)

Bases: ArraysInterface

An arrays interface for the case when the arrays are not actually distributed.

Parameters
  • num_global_elements (int) – The total number of objective function “elements”, i.e. the size of the objective function array f.

  • num_global_params (int) – The total number of (model) parameters, i.e. the size of the x array.

allocate_jtf(self)

Allocate an array for holding a ‘jtf’-type value.

Returns

numpy.ndarray or LocalNumpyArray

allocate_jtj(self)

Allocate an array for holding an approximated Hessian (type ‘jtj’).

Returns

numpy.ndarray or LocalNumpyArray

allocate_jac(self)

Allocate an array for holding a Jacobian matrix (type ‘ep’).

Returns

numpy.ndarray or LocalNumpyArray

deallocate_jtf(self, jtf)

Free an array for holding an objective function value (type ‘jtf’).

Returns

None

deallocate_jtj(self, jtj)

Free an array for holding an approximated Hessian (type ‘jtj’).

Returns

None

deallocate_jac(self, jac)

Free an array for holding a Jacobian matrix (type ‘ep’).

Returns

None

global_num_elements(self)

The total number of objective function “elements”.

This is the size/length of the objective function f vector.

Returns

int

jac_param_slice(self, only_if_leader=False)

The slice into a Jacobian’s columns that belong to this processor.

Parameters

only_if_leader (bool, optional) – If True, the current processor’s parameter slice is ony returned if the processor is the “leader” (i.e. the first) of the processors that calculate the same parameter slice. All non-leader processors return the zero-slice slice(0,0).

Returns

slice

jtf_param_slice(self)

The slice into a ‘jtf’ vector giving the rows of owned by this processor.

Returns

slice

param_fine_info(self)

Returns information regarding how model parameters are distributed among hosts and processors.

This information relates to the “fine” distribution used in distributed layouts, and is needed by some algorithms which utilize shared-memory communication between processors on the same host.

Returns

  • param_fine_slices_by_host (list) – A list with one entry per host. Each entry is itself a list of (rank, (global_param_slice, host_param_slice)) elements where rank is the top-level overall rank of a processor, global_param_slice is the parameter slice that processor owns and host_param_slice is the same slice relative to the parameters owned by the host.

  • owner_host_and_rank_of_global_fine_param_index (dict) – A mapping between parameter indices (keys) and the owning processor rank and host index. Values are (host_index, processor_rank) tuples.

allgather_x(self, x, global_x)

Gather a parameter (x) vector onto all the processors.

Parameters
Returns

None

allscatter_x(self, global_x, x)

Pare down an already-scattered global parameter (x) vector to be just a local x vector.

Parameters
  • global_x (numpy.array or LocalNumpyArray) – The input vector. This global vector is already present on all the processors, so there’s no need to do any MPI communication.

  • x (numpy.array or LocalNumpyArray) – The output vector, typically a slice of global_x..

Returns

None

scatter_x(self, global_x, x)

Scatter a global parameter (x) vector onto all the processors.

Parameters
Returns

None

allgather_f(self, f, global_f)

Gather an objective funtion (f) vector onto all the processors.

Parameters
Returns

None

gather_jtj(self, jtj, return_shared=False)

Gather a Hessian (jtj) matrix onto the root processor.

Parameters
  • jtj (numpy.array or LocalNumpyArray) – The (local) input matrix to gather.

  • return_shared (bool, optional) – Whether the returned array is allowed to be a shared-memory array, which results in a small performance gain because the array used internally to gather the results can be returned directly. When True a shared memory handle is also returned, and the caller assumes responsibilty for freeing the memory via :function:`pygsti.tools.sharedmemtools.cleanup_shared_ndarray`.

Returns

  • gathered_array (numpy.ndarray or None) – The full (global) output array on the root (rank=0) processor and None on all other processors.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – Returned only when return_shared == True. The shared memory handle associated with gathered_array, which is needed to free the memory.

scatter_jtj(self, global_jtj, jtj)

Scatter a Hessian (jtj) matrix onto all the processors.

Parameters
  • global_jtj (numpy.ndarray) – The global Hessian matrix to scatter.

  • jtj (numpy.ndarray or LocalNumpyArray) – The local destination array.

Returns

None

gather_jtf(self, jtf, return_shared=False)

Gather a jtf vector onto the root processor.

Parameters
  • jtf (numpy.array or LocalNumpyArray) – The local input vector to gather.

  • return_shared (bool, optional) – Whether the returned array is allowed to be a shared-memory array, which results in a small performance gain because the array used internally to gather the results can be returned directly. When True a shared memory handle is also returned, and the caller assumes responsibilty for freeing the memory via :function:`pygsti.tools.sharedmemtools.cleanup_shared_ndarray`.

Returns

  • gathered_array (numpy.ndarray or None) – The full (global) output array on the root (rank=0) processor and None on all other processors.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – Returned only when return_shared == True. The shared memory handle associated with gathered_array, which is needed to free the memory.

scatter_jtf(self, global_jtf, jtf)

Scatter a jtf vector onto all the processors.

Parameters
  • global_jtf (numpy.ndarray) – The global vector to scatter.

  • jtf (numpy.ndarray or LocalNumpyArray) – The local destination array.

Returns

None

global_svd_dot(self, jac_v, minus_jtf)

Gathers the dot product between a jtj-type matrix and a jtf-type vector into a global result array.

This is typically used within SVD-defined basis calculations, where jac_v is the “V” matrix of the SVD of a jacobian, and minus_jtf is the negative dot product between the Jacobian matrix and objective function vector.

Parameters
Returns

numpy.ndarray – The global (gathered) parameter vector dot(jac_v.T, minus_jtf).

fill_dx_svd(self, jac_v, global_vec, dx)

Computes the dot product of a jtj-type array with a global parameter array.

The result (dx) is a jtf-type array. This is typically used for computing the x-update vector in the LM method when using a SVD-defined basis.

Parameters
  • jac_v (numpy.ndarray or LocalNumpyArray) – An array of jtj-type.

  • global_vec (numpy.ndarray) – A global parameter vector.

  • dx (numpy.ndarray or LocalNumpyArray) – An array of jtf-type. Filled with dot(jac_v, global_vec) values.

Returns

None

dot_x(self, x1, x2)

Take the dot product of two x-type vectors.

Parameters
Returns

float

norm2_x(self, x)

Compute the Frobenius norm squared of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

infnorm_x(self, x)

Compute the infinity-norm of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

max_x(self, x)

Compute the maximum of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

norm2_f(self, f)

Compute the Frobenius norm squared of an f-type vector.

Parameters

f (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

norm2_jtj(self, jtj)

Compute the Frobenius norm squared of an jtj-type matrix.

Parameters

jtj (numpy.ndarray or LocalNumpyArray) – The array to operate on.

Returns

float

norm2_jac(self, j)

Compute the Frobenius norm squared of an Jacobian matrix (ep-type).

Parameters

j (numpy.ndarray or LocalNumpyArray) – The Jacobian to operate on.

Returns

float

fill_jtf(self, j, f, jtf)

Compute dot(Jacobian.T, f) in supplied memory.

Parameters
  • j (numpy.ndarray or LocalNumpyArray) – Jacobian matrix (type ep).

  • f (numpy.ndarray or LocalNumpyArray) – Objective function vector (type e).

  • jtf (numpy.ndarray or LocalNumpyArray) – Output array, type jtf. Filled with dot(j.T, f) values.

Returns

None

fill_jtj(self, j, jtj, shared_mem_buf=None)

Compute dot(Jacobian.T, Jacobian) in supplied memory.

Parameters
  • j (numpy.ndarray or LocalNumpyArray) – Jacobian matrix (type ep).

  • jtf (numpy.ndarray or LocalNumpyArray) – Output array, type jtj. Filled with dot(j.T, j) values.

  • shared_mem_buf (tuple or None) – Scratch space of shared memory used to speed up repeated calls to fill_jtj. If not none, the value returned from :method:`allocate_jtj_shared_mem_buf`.

Returns

None

allocate_jtj_shared_mem_buf(self)

Allocate scratch space to be used for repeated calls to :method:`fill_jtj`.

Returns

  • scratch (numpy.ndarray or None) – The scratch array.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – The shared memory handle associated with scratch, which is needed to free the memory.

deallocate_jtj_shared_mem_buf(self, jtj_buf)

Frees the scratch memory allocated by :method:`allocate_jtj_shared_mem_buf`.

Parameters

jtj_buf (tuple or None) – The value returned from :method:`allocate_jtj_shared_mem_buf`

jtj_diag_indices(self, jtj)

The indices into a jtj-type array that correspond to diagonal elements of the global matrix.

If jtj were a global quantity, then this would just be numpy.diag_indices_from(jtj), however, it may be more complicated in actuality when different processors hold different sections of the global matrix.

Parameters

jtj (numpy.ndarray or None) – The jtj-type array to get the indices with respect to.

Returns

tuple – A tuple of 1D arrays that can be used to index the elements of jtj that correspond to diagonal elements of the global jtj matrix.

class pygsti.optimize.DistributedArraysInterface(dist_layout, extra_elements=0)

Bases: ArraysInterface

An arrays interface where the arrays are distributed according to a distributed layout.

Parameters
  • dist_layout (DistributableCOPALayout) – The layout giving the distribution of the arrays.

  • extra_elements (int, optional) – The number of additional objective function “elements” beyond those specified by dist_layout. These are often used for penalty terms.

allocate_jtf(self)

Allocate an array for holding a ‘jtf’-type value.

Returns

numpy.ndarray or LocalNumpyArray

allocate_jtj(self)

Allocate an array for holding an approximated Hessian (type ‘jtj’).

Returns

numpy.ndarray or LocalNumpyArray

allocate_jac(self)

Allocate an array for holding a Jacobian matrix (type ‘ep’).

Returns

numpy.ndarray or LocalNumpyArray

deallocate_jtf(self, jtf)

Free an array for holding an objective function value (type ‘jtf’).

Returns

None

deallocate_jtj(self, jtj)

Free an array for holding an approximated Hessian (type ‘jtj’).

Returns

None

deallocate_jac(self, jac)

Free an array for holding a Jacobian matrix (type ‘ep’).

Returns

None

global_num_elements(self)

The total number of objective function “elements”.

This is the size/length of the objective function f vector.

Returns

int

jac_param_slice(self, only_if_leader=False)

The slice into a Jacobian’s columns that belong to this processor.

Parameters

only_if_leader (bool, optional) – If True, the current processor’s parameter slice is ony returned if the processor is the “leader” (i.e. the first) of the processors that calculate the same parameter slice. All non-leader processors return the zero-slice slice(0,0).

Returns

slice

jtf_param_slice(self)

The slice into a ‘jtf’ vector giving the rows of owned by this processor.

Returns

slice

param_fine_info(self)

Returns information regarding how model parameters are distributed among hosts and processors.

This information relates to the “fine” distribution used in distributed layouts, and is needed by some algorithms which utilize shared-memory communication between processors on the same host.

Returns

  • param_fine_slices_by_host (list) – A list with one entry per host. Each entry is itself a list of (rank, (global_param_slice, host_param_slice)) elements where rank is the top-level overall rank of a processor, global_param_slice is the parameter slice that processor owns and host_param_slice is the same slice relative to the parameters owned by the host.

  • owner_host_and_rank_of_global_fine_param_index (dict) – A mapping between parameter indices (keys) and the owning processor rank and host index. Values are (host_index, processor_rank) tuples.

allgather_x(self, x, global_x)

Gather a parameter (x) vector onto all the processors.

Parameters
Returns

None

allscatter_x(self, global_x, x)

Pare down an already-scattered global parameter (x) vector to be just a local x vector.

Parameters
  • global_x (numpy.array or LocalNumpyArray) – The input vector. This global vector is already present on all the processors, so there’s no need to do any MPI communication.

  • x (numpy.array or LocalNumpyArray) – The output vector, typically a slice of global_x..

Returns

None

scatter_x(self, global_x, x)

Scatter a global parameter (x) vector onto all the processors.

Parameters
Returns

None

allgather_f(self, f, global_f)

Gather an objective funtion (f) vector onto all the processors.

Parameters
Returns

None

gather_jtj(self, jtj, return_shared=False)

Gather a Hessian (jtj) matrix onto the root processor.

Parameters
  • jtj (numpy.array or LocalNumpyArray) – The (local) input matrix to gather.

  • return_shared (bool, optional) – Whether the returned array is allowed to be a shared-memory array, which results in a small performance gain because the array used internally to gather the results can be returned directly. When True a shared memory handle is also returned, and the caller assumes responsibilty for freeing the memory via :function:`pygsti.tools.sharedmemtools.cleanup_shared_ndarray`.

Returns

  • gathered_array (numpy.ndarray or None) – The full (global) output array on the root (rank=0) processor and None on all other processors.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – Returned only when return_shared == True. The shared memory handle associated with gathered_array, which is needed to free the memory.

scatter_jtj(self, global_jtj, jtj)

Scatter a Hessian (jtj) matrix onto all the processors.

Parameters
  • global_jtj (numpy.ndarray) – The global Hessian matrix to scatter.

  • jtj (numpy.ndarray or LocalNumpyArray) – The local destination array.

Returns

None

gather_jtf(self, jtf, return_shared=False)

Gather a jtf vector onto the root processor.

Parameters
  • jtf (numpy.array or LocalNumpyArray) – The local input vector to gather.

  • return_shared (bool, optional) – Whether the returned array is allowed to be a shared-memory array, which results in a small performance gain because the array used internally to gather the results can be returned directly. When True a shared memory handle is also returned, and the caller assumes responsibilty for freeing the memory via :function:`pygsti.tools.sharedmemtools.cleanup_shared_ndarray`.

Returns

  • gathered_array (numpy.ndarray or None) – The full (global) output array on the root (rank=0) processor and None on all other processors.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – Returned only when return_shared == True. The shared memory handle associated with gathered_array, which is needed to free the memory.

scatter_jtf(self, global_jtf, jtf)

Scatter a jtf vector onto all the processors.

Parameters
  • global_jtf (numpy.ndarray) – The global vector to scatter.

  • jtf (numpy.ndarray or LocalNumpyArray) – The local destination array.

Returns

None

global_svd_dot(self, jac_v, minus_jtf)

Gathers the dot product between a jtj-type matrix and a jtf-type vector into a global result array.

This is typically used within SVD-defined basis calculations, where jac_v is the “V” matrix of the SVD of a jacobian, and minus_jtf is the negative dot product between the Jacobian matrix and objective function vector.

Parameters
Returns

numpy.ndarray – The global (gathered) parameter vector dot(jac_v.T, minus_jtf).

fill_dx_svd(self, jac_v, global_vec, dx)

Computes the dot product of a jtj-type array with a global parameter array.

The result (dx) is a jtf-type array. This is typically used for computing the x-update vector in the LM method when using a SVD-defined basis.

Parameters
  • jac_v (numpy.ndarray or LocalNumpyArray) – An array of jtj-type.

  • global_vec (numpy.ndarray) – A global parameter vector.

  • dx (numpy.ndarray or LocalNumpyArray) – An array of jtf-type. Filled with dot(jac_v, global_vec) values.

Returns

None

dot_x(self, x1, x2)

Take the dot product of two x-type vectors.

Parameters
Returns

float

norm2_x(self, x)

Compute the Frobenius norm squared of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

infnorm_x(self, x)

Compute the infinity-norm of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

min_x(self, x)

Compute the minimum of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

max_x(self, x)

Compute the maximum of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

norm2_f(self, f)

Compute the Frobenius norm squared of an f-type vector.

Parameters

f (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

norm2_jac(self, j)

Compute the Frobenius norm squared of an Jacobian matrix (ep-type).

Parameters

j (numpy.ndarray or LocalNumpyArray) – The Jacobian to operate on.

Returns

float

norm2_jtj(self, jtj)

Compute the Frobenius norm squared of an jtj-type matrix.

Parameters

jtj (numpy.ndarray or LocalNumpyArray) – The array to operate on.

Returns

float

fill_jtf(self, j, f, jtf)

Compute dot(Jacobian.T, f) in supplied memory.

Parameters
  • j (numpy.ndarray or LocalNumpyArray) – Jacobian matrix (type ep).

  • f (numpy.ndarray or LocalNumpyArray) – Objective function vector (type e).

  • jtf (numpy.ndarray or LocalNumpyArray) – Output array, type jtf. Filled with dot(j.T, f) values.

Returns

None

fill_jtj(self, j, jtj, shared_mem_buf=None)

Compute dot(Jacobian.T, Jacobian) in supplied memory.

Parameters
  • j (numpy.ndarray or LocalNumpyArray) – Jacobian matrix (type ep).

  • jtf (numpy.ndarray or LocalNumpyArray) – Output array, type jtj. Filled with dot(j.T, j) values.

  • shared_mem_buf (tuple or None) – Scratch space of shared memory used to speed up repeated calls to fill_jtj. If not none, the value returned from :method:`allocate_jtj_shared_mem_buf`.

Returns

None

allocate_jtj_shared_mem_buf(self)

Allocate scratch space to be used for repeated calls to :method:`fill_jtj`.

Returns

  • scratch (numpy.ndarray or None) – The scratch array.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – The shared memory handle associated with scratch, which is needed to free the memory.

deallocate_jtj_shared_mem_buf(self, jtj_buf)

Frees the scratch memory allocated by :method:`allocate_jtj_shared_mem_buf`.

Parameters

jtj_buf (tuple or None) – The value returned from :method:`allocate_jtj_shared_mem_buf`

jtj_diag_indices(self, jtj)

The indices into a jtj-type array that correspond to diagonal elements of the global matrix.

If jtj were a global quantity, then this would just be numpy.diag_indices_from(jtj), however, it may be more complicated in actuality when different processors hold different sections of the global matrix.

Parameters

jtj (numpy.ndarray or None) – The jtj-type array to get the indices with respect to.

Returns

tuple – A tuple of 1D arrays that can be used to index the elements of jtj that correspond to diagonal elements of the global jtj matrix.

pygsti.optimize._custom_solve(a, b, x, ari, resource_alloc, proc_threshold=100)

Simple parallel Gaussian Elimination with pivoting.

This function was built to provide a parallel alternative to scipy.linalg.solve, and can achieve faster runtimes compared with the serial SciPy routine when the number of available processors and problem size are large enough.

When the number of processors is greater than proc_threshold (below this number the routine just calls scipy.linalg.solve on the root processor) the method works as follows:

  • each processor “owns” some subset of the rows of a and b.

  • iteratively (over pivot columns), the best pivot row is found, and this row is used to eliminate all other elements in the current pivot column. This procedure operations on the joined matrix a|b, and when it completes the matrix a is in reduced row echelon form (RREF).

  • back substitution (trivial because a is in reduced REF) is performed to find the solution x such that a @ x = b.

Parameters
  • a (LocalNumpyArray) – A 2D array with the ‘jtj’ distribution, holding the rows of the a matrix belonging to the current processor. (This belonging is dictated by the “fine” distribution in a distributed layout.)

  • b (LocalNumpyArray) – A 1D array with the ‘jtf’ distribution, holding the rows of the b vector belonging to the current processor.

  • x (LocalNumpyArray) – A 1D array with the ‘jtf’ distribution, holding the rows of the x vector belonging to the current processor. This vector is filled by this function.

  • ari (ArraysInterface) – An object that provides an interface for creating and manipulating data arrays.

  • resource_alloc (ResourceAllocation) – Gives the resources (e.g., processors and memory) available for use.

  • proc_threshold (int, optional) – Below this number of processors this routine will simply gather a and b to a single (the rank 0) processor, call SciPy’s serial linear solver, scipy.linalg.solve, and scatter the results back onto all the processors.

Returns

None

class pygsti.optimize._VerbosityPrinter(verbosity=1, filename=None, comm=None, warnings=True, split=False, clear_file=True)

Bases: object

Class responsible for logging things to stdout or a file.

Controls verbosity and can print progress bars. ex:

>>> VerbosityPrinter(1)

would construct a printer that printed out messages of level one or higher to the screen.

>>> VerbosityPrinter(3, 'output.txt')

would construct a printer that sends verbose output to a text file

The static function create_printer() will construct a printer from either an integer or an already existing printer. it is a static method of the VerbosityPrinter class, so it is called like so:

>>> VerbosityPrinter.create_printer(2)

or

>>> VerbostityPrinter.create_printer(VerbosityPrinter(3, 'output.txt'))

printer.log('status') would log ‘status’ if the printers verbosity was one or higher. printer.log('status2', 2) would log ‘status2’ if the printer’s verbosity was two or higher

printer.error('something terrible happened') would ALWAYS log ‘something terrible happened’. printer.warning('something worrisome happened') would log if verbosity was one or higher - the same as a normal status.

Both printer.error and printer.warning will prepend ‘ERROR: ‘ or ‘WARNING: ‘ to the message they are given. Optionally, printer.log() can also prepend ‘Status_n’ to the message, where n is the message level.

Logging of progress bars/iterations:

>>> with printer_instance.progress_logging(verbosity):
>>>     for i, item in enumerate(data):
>>>         printer.show_progress(i, len(data))
>>>         printer.log(...)

will output either a progress bar or iteration statuses depending on the printer’s verbosity

Parameters
  • verbosity (int) – How verbose the printer should be.

  • filename (str, optional) – Where to put output (If none, output goes to screen)

  • comm (mpi4py.MPI.Comm or ResourceAllocation, optional) – Restricts output if the program is running in parallel (By default, if the rank is 0, output is sent to screen, and otherwise sent to commfiles 1, 2, …

  • warnings (bool, optional) – Whether or not to print warnings

  • split (bool, optional) – Whether to split output between stdout and stderr as appropriate, or to combine the streams so everything is sent to stdout.

  • clear_file (bool, optional) – Whether or not filename should be cleared (overwritten) or simply appended to.

_comm_path

relative path where comm files (outputs of non-root ranks) are stored.

Type

str

_comm_file_name

root filename for comm files (outputs of non-root ranks).

Type

str

_comm_file_ext

filename extension for comm files (outputs of non-root ranks).

Type

str

_comm_path =
_comm_file_name =
_comm_file_ext = .txt
_create_file(self, filename)
_get_comm_file(self, comm_id)
clone(self)

Instead of deepcopy, initialize a new printer object and feed it some select deepcopied members

Returns

VerbosityPrinter

static create_printer(verbosity, comm=None)

Function for converting between interfaces

Parameters
  • verbosity (int or VerbosityPrinter object, required:) – object to build a printer from

  • comm (mpi4py.MPI.Comm object, optional) – Comm object to build printers with. !Will override!

Returns

VerbosityPrinter – The printer object, constructed from either an integer or another printer

__add__(self, other)

Increase the verbosity of a VerbosityPrinter

__sub__(self, other)

Decrease the verbosity of a VerbosityPrinter

__getstate__(self)
__setstate__(self, state_dict)
_append_to(self, filename, message)
_put(self, message, flush=True, stderr=False)
_record(self, typ, level, message)
error(self, message)

Log an error to the screen/file

Parameters

message (str) – the error message

Returns

None

warning(self, message)

Log a warning to the screen/file if verbosity > 1

Parameters

message (str) – the warning message

Returns

None

log(self, message, message_level=None, indent_char='  ', show_statustype=False, do_indent=True, indent_offset=0, end='\n', flush=True)

Log a status message to screen/file.

Determines whether the message should be printed based on current verbosity setting, then sends the message to the appropriate output

Parameters
  • message (str) – the message to print (or log)

  • message_level (int, optional) – the minimum verbosity level at which this level is printed.

  • indent_char (str, optional) – what constitutes an “indent” (messages at higher levels are indented more when do_indent=True).

  • show_statustype (bool, optional) – if True, prepend lines with “Status Level X” indicating the message_level.

  • do_indent (bool, optional) – whether messages at higher message levels should be indented. Note that if this is False it may be helpful to set show_statustype=True.

  • indent_offset (int, optional) – an additional number of indentations to add, on top of any due to the message level.

  • end (str, optional) – the character (or string) to end message lines with.

  • flush (bool, optional) – whether stdout should be flushed right after this message is printed (this avoids delays in on-screen output due to buffering).

Returns

None

_progress_bar(self, iteration, total, bar_length, num_decimals, fill_char, empty_char, prefix, suffix, indent)
_verbose_iteration(self, iteration, total, prefix, suffix, verbose_messages, indent, end)
__str__(self)

Return str(self).

verbosity_env(self, level)

Create a temporary environment with a different verbosity level.

This is context manager, controlled using Python’s with statement:

>>> with printer.verbosity_env(2):
        printer.log('Message1') # printed at verbosity level 2
        printer.log('Message2') # printed at verbosity level 2
Parameters

level (int) – the verbosity level of the environment.

progress_logging(self, message_level=1)

Context manager for logging progress bars/iterations.

(The printer will return to its normal, unrestricted state when the progress logging has finished)

Parameters

message_level (int, optional) – progress messages will not be shown until the verbosity level reaches message_level.

show_progress(self, iteration, total, bar_length=50, num_decimals=2, fill_char='#', empty_char='-', prefix='Progress:', suffix='', verbose_messages=[], indent_char='  ', end='\n')

Displays a progress message (to be used within a progress_logging block).

Parameters
  • iteration (int) – the 0-based current iteration – the interation number this message is for.

  • total (int) – the total number of iterations expected.

  • bar_length (int, optional) – the length, in characters, of a text-format progress bar (only used when the verbosity level is exactly equal to the progress_logging message level.

  • num_decimals (int, optional) – number of places after the decimal point that are displayed in progress bar’s percentage complete.

  • fill_char (str, optional) – replaces ‘#’ as the bar-filling character

  • empty_char (str, optional) – replaces ‘-’ as the empty-bar character

  • prefix (str, optional) – message in front of the bar

  • suffix (str, optional) – message after the bar

  • verbose_messages (list, optional) – A list of strings to display after an initial “Iter X of Y” line when the verbosity level is higher than the progress_logging message level and so more verbose messages are shown (and a progress bar is not). The elements of verbose_messages will occur, one per line, after the initial “Iter X of Y” line.

  • indent_char (str, optional) – what constitutes an “indentation”.

  • end (str, optional) – the character (or string) to end message lines with.

Returns

None

_end_progress(self)
start_recording(self)

Begins recording the output (to memory).

Begins recording (in memory) a list of (type, verbosityLevel, message) tuples that is returned by the next call to :method:`stop_recording`.

Returns

None

is_recording(self)

Returns whether this VerbosityPrinter is currently recording.

Returns

bool

stop_recording(self)

Stops recording and returns recorded output.

Stops a “recording” started by :method:`start_recording` and returns the list of (type, verbosityLevel, message) tuples that have been recorded since then.

Returns

list

class pygsti.optimize._ResourceAllocation(comm=None, mem_limit=None, profiler=None, distribute_method='default', allocated_memory=0)

Bases: object

Describes available resources and how they should be allocated.

This includes the number of processors and amount of memory, as well as a strategy for how computations should be distributed among them.

Parameters
  • comm (mpi4py.MPI.Comm, optional) – MPI communicator holding the number of available processors.

  • mem_limit (int, optional) – A rough per-processor memory limit in bytes.

  • profiler (Profiler, optional) – A lightweight profiler object for tracking resource usage.

  • distribute_method (str, optional) – The name of a distribution strategy.

classmethod cast(cls, arg)

Cast arg to a ResourceAllocation object.

If arg already is a ResourceAllocation instance, it just returned. Otherwise this function attempts to create a new instance from arg.

Parameters

arg (ResourceAllocation or dict) – An object that can be cast to a ResourceAllocation.

Returns

ResourceAllocation

build_hostcomms(self)
property comm_rank(self)

A safe way to get self.comm.rank (0 if self.comm is None)

property comm_size(self)

A safe way to get self.comm.size (1 if self.comm is None)

property is_host_leader(self)

True if this processors is the rank-0 “leader” of its host (node). False otherwise.

host_comm_barrier(self)

Calls self.host_comm.barrier() when self.host_comm is not None.

This convenience function provides an often-used barrier that follows code where a single “leader” processor modifies a memory block shared between all members of self.host_comm, and the other processors must wait until this modification is performed before proceeding with their own computations.

Returns

None

copy(self)

Copy this object.

Returns

ResourceAllocation

reset(self, allocated_memory=0)

Resets internal allocation counters to given values (defaults to zero).

Parameters

allocated_memory (int64) – The value to set the memory allocation counter to.

Returns

None

add_tracked_memory(self, num_elements, dtype='d')

Adds nelements * itemsize bytes to the total amount of allocated memory being tracked.

If the total (tracked) memory exceeds self.mem_limit a MemoryError exception is raised.

Parameters
  • num_elements (int) – The number of elements to track allocation of.

  • dtype (numpy.dtype, optional) – The type of elements, needed to compute the number of bytes per element.

Returns

None

check_can_allocate_memory(self, num_elements, dtype='d')

Checks that allocating nelements doesn’t cause the memory limit to be exceeded.

This memory isn’t tracked - it’s just added to the current tracked memory and a MemoryError exception is raised if the result exceeds self.mem_limit.

Parameters
  • num_elements (int) – The number of elements to track allocation of.

  • dtype (numpy.dtype, optional) – The type of elements, needed to compute the number of bytes per element.

Returns

None

temporarily_track_memory(self, num_elements, dtype='d')

Temporarily adds nelements to tracked memory (a context manager).

A MemoryError exception is raised if the tracked memory exceeds self.mem_limit.

Parameters
  • num_elements (int) – The number of elements to track allocation of.

  • dtype (numpy.dtype, optional) – The type of elements, needed to compute the number of bytes per element.

Returns

contextmanager

gather_base(self, result, local, slice_of_global, unit_ralloc=None, all_gather=False)

Gather or all-gather operation using local arrays and a unit resource allocation.

Similar to a normal MPI gather call, but more easily integrates with a hierarchy of processor divisions, or nested comms, by taking a unit_ralloc argument. This is essentially another comm that specifies the groups of processors that have all computed the same local array, i.e., slice of the final to-be gathered array. So, when gathering the result, only processors with unit_ralloc.rank == 0 need to contribute to the gather operation.

Parameters
  • result (numpy.ndarray, possibly shared) – The destination “global” array. When shared memory is being used, i.e. when this ResourceAllocation object has a nontrivial inter-host comm, this array must be allocated as a shared array using this ralloc or a larger so that result is shared between all the processors for this resource allocation’s intra-host communicator. This allows a speedup when shared memory is used by having multiple smaller gather operations in parallel instead of one large gather.

  • local (numpy.ndarray) – The locally computed quantity. This can be a shared-memory array, but need not be.

  • slice_of_global (slice or numpy.ndarray) – The slice of result that local constitutes, i.e., in the end result[slice_of_global] = local. This may be a Python slice or a NumPy array of indices.

  • unit_ralloc (ResourceAllocation, optional) – A resource allocation (essentially a comm) for the group of processors that all compute the same local result, so that only the unit_ralloc.rank == 0 processors will contribute to the gather operation. If None, then it is assumed that all processors compute different local results.

  • all_gather (bool, optional) – Whether the final result should be gathered on all the processors of this ResourceAllocation or just the root (rank 0) processor.

Returns

None

gather(self, result, local, slice_of_global, unit_ralloc=None)

Gather local arrays into a global result array potentially with a unit resource allocation.

Similar to a normal MPI gather call, but more easily integrates with a hierarchy of processor divisions, or nested comms, by taking a unit_ralloc argument. This is essentially another comm that specifies the groups of processors that have all computed the same local array, i.e., slice of the final to-be gathered array. So, when gathering the result, only processors with unit_ralloc.rank == 0 need to contribute to the gather operation.

The global array is only gathered on the root (rank 0) processor of this resource allocation.

Parameters
  • result (numpy.ndarray, possibly shared) – The destination “global” array, only needed on the root (rank 0) processor. When shared memory is being used, i.e. when this ResourceAllocation object has a nontrivial inter-host comm, this array must be allocated as a shared array using this ralloc or a larger so that result is shared between all the processors for this resource allocation’s intra-host communicator. This allows a speedup when shared memory is used by having multiple smaller gather operations in parallel instead of one large gather.

  • local (numpy.ndarray) – The locally computed quantity. This can be a shared-memory array, but need not be.

  • slice_of_global (slice or numpy.ndarray) – The slice of result that local constitutes, i.e., in the end result[slice_of_global] = local. This may be a Python slice or a NumPy array of indices.

  • unit_ralloc (ResourceAllocation, optional) – A resource allocation (essentially a comm) for the group of processors that all compute the same local result, so that only the unit_ralloc.rank == 0 processors will contribute to the gather operation. If None, then it is assumed that all processors compute different local results.

Returns

None

allgather(self, result, local, slice_of_global, unit_ralloc=None)

All-gather local arrays into global arrays on each processor, potentially using a unit resource allocation.

Similar to a normal MPI gather call, but more easily integrates with a hierarchy of processor divisions, or nested comms, by taking a unit_ralloc argument. This is essentially another comm that specifies the groups of processors that have all computed the same local array, i.e., slice of the final to-be gathered array. So, when gathering the result, only processors with unit_ralloc.rank == 0 need to contribute to the gather operation.

Parameters
  • result (numpy.ndarray, possibly shared) – The destination “global” array. When shared memory is being used, i.e. when this ResourceAllocation object has a nontrivial inter-host comm, this array must be allocated as a shared array using this ralloc or a larger so that result is shared between all the processors for this resource allocation’s intra-host communicator. This allows a speedup when shared memory is used by having multiple smaller gather operations in parallel instead of one large gather.

  • local (numpy.ndarray) – The locally computed quantity. This can be a shared-memory array, but need not be.

  • slice_of_global (slice or numpy.ndarray) – The slice of result that local constitutes, i.e., in the end result[slice_of_global] = local. This may be a Python slice or a NumPy array of indices.

  • unit_ralloc (ResourceAllocation, optional) – A resource allocation (essentially a comm) for the group of processors that all compute the same local result, so that only the unit_ralloc.rank == 0 processors will contribute to the gather operation. If None, then it is assumed that all processors compute different local results.

Returns

None

allreduce_sum(self, result, local, unit_ralloc=None)

Sum local arrays on different processors, potentially using a unit resource allocation.

Similar to a normal MPI reduce call (with MPI.SUM type), but more easily integrates with a hierarchy of processor divisions, or nested comms, by taking a unit_ralloc argument. This is essentially another comm that specifies the groups of processors that have all computed the same local array. So, when performing the sum, only processors with unit_ralloc.rank == 0 contribute to the sum. This handles the case where simply summing the local contributions from all processors would result in over-counting because of multiple processors hold the same logical result (summand).

Parameters
  • result (numpy.ndarray, possibly shared) – The destination “global” array, with the same shape as all the local arrays being summed. This can be any shape (including any number of dimensions). When shared memory is being used, i.e. when this ResourceAllocation object has a nontrivial inter-host comm, this array must be allocated as a shared array using this ralloc or a larger so that result is shared between all the processors for this resource allocation’s intra-host communicator. This allows a speedup when shared memory is used by distributing computation of result over each host’s processors and performing these sums in parallel.

  • local (numpy.ndarray) – The locally computed quantity. This can be a shared-memory array, but need not be.

  • unit_ralloc (ResourceAllocation, optional) – A resource allocation (essentially a comm) for the group of processors that all compute the same local result, so that only the unit_ralloc.rank == 0 processors will contribute to the sum operation. If None, then it is assumed that all processors compute different local results.

Returns

None

allreduce_sum_simple(self, local, unit_ralloc=None)

A simplified sum over quantities on different processors that doesn’t use shared memory.

The shared memory usage of :method:`allreduce_sum` can be overkill when just summing a single scalar quantity. This method provides a way to easily sum a quantity across all the processors in this ResourceAllocation object using a unit resource allocation.

Parameters
  • local (int or float) – The local (per-processor) value to sum.

  • unit_ralloc (ResourceAllocation, optional) – A resource allocation (essentially a comm) for the group of processors that all compute the same local value, so that only the unit_ralloc.rank == 0 processors will contribute to the sum. If None, then it is assumed that each processor computes a logically different local value.

Returns

float or int – The sum of all local quantities, returned on all the processors.

allreduce_min(self, result, local, unit_ralloc=None)

Take elementwise min of local arrays on different processors, potentially using a unit resource allocation.

Similar to a normal MPI reduce call (with MPI.MIN type), but more easily integrates with a hierarchy of processor divisions, or nested comms, by taking a unit_ralloc argument. This is essentially another comm that specifies the groups of processors that have all computed the same local array. So, when performing the min operation, only processors with unit_ralloc.rank == 0 contribute.

Parameters
  • result (numpy.ndarray, possibly shared) – The destination “global” array, with the same shape as all the local arrays being operated on. This can be any shape (including any number of dimensions). When shared memory is being used, i.e. when this ResourceAllocation object has a nontrivial inter-host comm, this array must be allocated as a shared array using this ralloc or a larger so that result is shared between all the processors for this resource allocation’s intra-host communicator. This allows a speedup when shared memory is used by distributing computation of result over each host’s processors and performing these sums in parallel.

  • local (numpy.ndarray) – The locally computed quantity. This can be a shared-memory array, but need not be.

  • unit_ralloc (ResourceAllocation, optional) – A resource allocation (essentially a comm) for the group of processors that all compute the same local result, so that only the unit_ralloc.rank == 0 processors will contribute to the sum operation. If None, then it is assumed that all processors compute different local results.

Returns

None

allreduce_max(self, result, local, unit_ralloc=None)

Take elementwise max of local arrays on different processors, potentially using a unit resource allocation.

Similar to a normal MPI reduce call (with MPI.MAX type), but more easily integrates with a hierarchy of processor divisions, or nested comms, by taking a unit_ralloc argument. This is essentially another comm that specifies the groups of processors that have all computed the same local array. So, when performing the max operation, only processors with unit_ralloc.rank == 0 contribute.

Parameters
  • result (numpy.ndarray, possibly shared) – The destination “global” array, with the same shape as all the local arrays being operated on. This can be any shape (including any number of dimensions). When shared memory is being used, i.e. when this ResourceAllocation object has a nontrivial inter-host comm, this array must be allocated as a shared array using this ralloc or a larger so that result is shared between all the processors for this resource allocation’s intra-host communicator. This allows a speedup when shared memory is used by distributing computation of result over each host’s processors and performing these sums in parallel.

  • local (numpy.ndarray) – The locally computed quantity. This can be a shared-memory array, but need not be.

  • unit_ralloc (ResourceAllocation, optional) – A resource allocation (essentially a comm) for the group of processors that all compute the same local result, so that only the unit_ralloc.rank == 0 processors will contribute to the sum operation. If None, then it is assumed that all processors compute different local results.

Returns

None

bcast(self, value, root=0)

Broadcasts a value from the root processor/host to the others in this resource allocation.

This is similar to a usual MPI broadcast, except it takes advantage of shared memory when it is available. When shared memory is being used, i.e. when this ResourceAllocation object has a nontrivial inter-host comm, then this routine places value in a shared memory buffer and uses the resource allocation’s inter-host communicator to broadcast the result from the root host to all the other hosts using all the processor on the root host in parallel (all processors with the same intra-host rank participate in a MPI broadcast).

Parameters
  • value (numpy.ndarray) – The value to broadcast. May be shared memory but doesn’t need to be. Only need to specify this on the rank root processor, other processors can provide any value for this argument (it’s unused).

  • root (int) – The rank of the processor whose value will be to broadcast.

Returns

numpy.ndarray – The broadcast value, in a new, non-shared-memory array.

__getstate__(self)
class pygsti.optimize._NicelySerializable

Bases: object

The base class for all “nicely serializable” objects in pyGSTi.

A “nicely serializable” object can be converted to and created from a native Python object (like a string or dict) that contains only other native Python objects. In addition, there are constraints on the makeup of these objects so that they can be easily serialized to standard text-based formats, e.g. JSON. For example, dictionary keys must be strings, and the list vs. tuple distinction cannot be assumed to be preserved during serialization.

classmethod read(cls, path, format=None)

Read an object of this type, or a subclass of this type, from a file.

Parameters
  • path (str or Path or file-like) – The filename to open or an already open input stream.

  • format ({'json', None}) – The format of the file. If None this is determined automatically by the filename extension of a given path.

Returns

NicelySerializable

classmethod load(cls, f, format='json')

Load an object of this type, or a subclass of this type, from an input stream.

Parameters
  • f (file-like) – An open input stream to read from.

  • format ({'json'}) – The format of the input stream data.

Returns

NicelySerializable

classmethod loads(cls, s, format='json')

Load an object of this type, or a subclass of this type, from a string.

Parameters
  • s (str) – The serialized object.

  • format ({'json'}) – The format of the string data.

Returns

NicelySerializable

classmethod from_nice_serialization(cls, state)

Create and initialize an object from a “nice” serialization.

A “nice” serialization here means one created by a prior call to to_nice_serialization using this class or a subclass of it. Nice serializations adhere to additional rules (e.g. that dictionary keys must be strings) that make them amenable to common file formats (e.g. JSON).

The state argument is typically a dictionary containing ‘module’ and ‘state’ keys specifying the type of object that should be created. This type must be this class or a subclass of it.

Parameters

state (object) – An object, usually a dictionary, representing the object to de-serialize.

Returns

object

to_nice_serialization(self)

Serialize this object in a way that adheres to “niceness” rules of common text file formats.

Returns

object – Usually a dictionary representing the serialized object, but may also be another native Python type, e.g. a string or list.

write(self, path, **format_kwargs)

Writes this object to a file.

Parameters
  • path (str or Path) – The name of the file that is written.

  • format ({'json', 'repr'}) – The format to write.

  • format_kwargs (dict, optional) – Additional arguments specific to the format being used. For example, the JSON format accepts indent as an argument because json.dump does.

Returns

None

dump(self, f, format='json', **format_kwargs)

Serializes and writes this object to a given output stream.

Parameters
  • f (file-like) – A writable output stream.

  • format ({'json', 'repr'}) – The format to write.

  • format_kwargs (dict, optional) – Additional arguments specific to the format being used. For example, the JSON format accepts indent as an argument because json.dump does.

Returns

None

dumps(self, format='json', **format_kwargs)

Serializes this object and returns it as a string.

Parameters
  • format ({'json', 'repr'}) – The format to write.

  • format_kwargs (dict, optional) – Additional arguments specific to the format being used. For example, the JSON format accepts indent as an argument because json.dump does.

Returns

str

_dump_or_dumps(self, f, format='json', **format_kwargs)

Serializes and writes this object to a given output stream.

Parameters
  • f (file-like) – A writable output stream. If None, then object is written as a string and returned.

  • format ({'json', 'repr'}) – The format to write.

  • format_kwargs (dict, optional) – Additional arguments specific to the format being used. For example, the JSON format accepts indent as an argument because json.dump does.

Returns

str or None – If f is None, then the serialized object as a string is returned. Otherwise, None is returned.

_to_nice_serialization(self)
classmethod _from_nice_serialization(cls, state)
classmethod _state_class(cls, state, check_is_subclass=True)

Returns the class specified by the given state dictionary

classmethod _check_compatible_nice_state(cls, state)
classmethod _encodemx(cls, mx)
classmethod _decodemx(cls, mx)
classmethod _encodevalue(cls, val)
classmethod _decodevalue(cls, val)
pygsti.optimize._MACH_PRECISION = 1e-12
class pygsti.optimize.OptimizerResult(objective_func, opt_x, opt_f=None, opt_jtj=None, opt_unpenalized_f=None, chi2_k_distributed_qty=None, optimizer_specific_qtys=None)

Bases: object

The result from an optimization.

Parameters
  • objective_func (ObjectiveFunction) – The objective function that was optimized.

  • opt_x (numpy.ndarray) – The optimal argument (x) value. Often a vector of parameters.

  • opt_f (numpy.ndarray) – the optimal objective function (f) value. Often this is the least-squares vector of objective function values.

  • opt_jtj (numpy.ndarray, optional) – the optimial dot(transpose(J),J) value, where J is the Jacobian matrix. This may be useful for computing approximate error bars.

  • opt_unpenalized_f (numpy.ndarray, optional) – the optimal objective function (f) value with any penalty terms removed.

  • chi2_k_distributed_qty (float, optional) – a value that is supposed to be chi2_k distributed.

  • optimizer_specific_qtys (dict, optional) – a dictionary of additional optimization parameters.

class pygsti.optimize.Optimizer

Bases: pygsti.baseobjs.nicelyserializable.NicelySerializable

An optimizer. Optimizes an objective function.

classmethod cast(cls, obj)

Cast obj to a Optimizer.

If obj is already an Optimizer it is just returned, otherwise this function tries to create a new object using obj as a dictionary of constructor arguments.

Parameters

obj (Optimizer or dict) – The object to cast.

Returns

Optimizer

class pygsti.optimize.CustomLMOptimizer(maxiter=100, maxfev=100, tol=1e-06, fditer=0, first_fditer=0, damping_mode='identity', damping_basis='diagonal_values', damping_clip=None, use_acceleration=False, uphill_step_threshold=0.0, init_munu='auto', oob_check_interval=0, oob_action='reject', oob_check_mode=0, serial_solve_proc_threshold=100)

Bases: Optimizer

A Levenberg-Marquardt optimizer customized for GST-like problems.

Parameters
  • maxiter (int, optional) – The maximum number of (outer) interations.

  • maxfev (int, optional) – The maximum function evaluations.

  • tol (float or dict, optional) – The tolerance, specified as a single float or as a dict with keys {‘relx’, ‘relf’, ‘jac’, ‘maxdx’}. A single float sets the ‘relf’ and ‘jac’ elemments and leaves the others at their default values.

  • fditer (int optional) – Internally compute the Jacobian using a finite-difference method for the first fditer iterations. This is useful when the initial point lies at a special or singular point where the analytic Jacobian is misleading.

  • first_fditer (int, optional) – Number of finite-difference iterations applied to the first stage of the optimization (only). Unused.

  • damping_mode ({'identity', 'JTJ', 'invJTJ', 'adaptive'}) – How damping is applied. ‘identity’ means that the damping parameter mu multiplies the identity matrix. ‘JTJ’ means that mu multiplies the diagonal or singular values (depending on scaling_mode) of the JTJ (Fischer information and approx. hessaian) matrix, whereas ‘invJTJ’ means mu multiplies the reciprocals of these values instead. The ‘adaptive’ mode adaptively chooses a damping strategy.

  • damping_basis ({'diagonal_values', 'singular_values'}) – Whether the the diagonal or singular values of the JTJ matrix are used during damping. If ‘singular_values’ is selected, then a SVD of the Jacobian (J) matrix is performed and damping is performed in the basis of (right) singular vectors. If ‘diagonal_values’ is selected, the diagonal values of relevant matrices are used as a proxy for the the singular values (saving the cost of performing a SVD).

  • damping_clip (tuple, optional) – A 2-tuple giving upper and lower bounds for the values that mu multiplies. If damping_mode == “identity” then this argument is ignored, as mu always multiplies a 1.0 on the diagonal if the identity matrix. If None, then no clipping is applied.

  • use_acceleration (bool, optional) – Whether to include a geodesic acceleration term as suggested in arXiv:1201.5885. This is supposed to increase the rate of convergence with very little overhead. In practice we’ve seen mixed results.

  • uphill_step_threshold (float, optional) – Allows uphill steps when taking two consecutive steps in nearly the same direction. The condition for accepting an uphill step is that (uphill_step_threshold-beta)*new_objective < old_objective, where beta is the cosine of the angle between successive steps. If uphill_step_threshold == 0 then no uphill steps are allowed, otherwise it should take a value between 1.0 and 2.0, with 1.0 being the most permissive to uphill steps.

  • init_munu (tuple, optional) – If not None, a (mu, nu) tuple of 2 floats giving the initial values for mu and nu.

  • oob_check_interval (int, optional) – Every oob_check_interval outer iterations, the objective function (obj_fn) is called with a second argument ‘oob_check’, set to True. In this case, obj_fn can raise a ValueError exception to indicate that it is Out Of Bounds. If oob_check_interval is 0 then this check is never performed; if 1 then it is always performed.

  • oob_action ({"reject","stop"}) – What to do when the objective function indicates (by raising a ValueError as described above). “reject” means the step is rejected but the optimization proceeds; “stop” means the optimization stops and returns as converged at the last known-in-bounds point.

  • oob_check_mode (int, optional) – An advanced option, expert use only. If 0 then the optimization is halted as soon as an attempt is made to evaluate the function out of bounds. If 1 then the optimization is halted only when a would-be accepted step is out of bounds.

  • serial_solve_proc_threshold (int optional) – When there are fewer than this many processors, the optimizer will solve linear systems serially, using SciPy on a single processor, rather than using a parallelized Gaussian Elimination (with partial pivoting) algorithm coded in Python. Since SciPy’s implementation is more efficient, it’s not worth using the parallel version until there are many processors to spread the work among.

_to_nice_serialization(self)
classmethod _from_nice_serialization(cls, state)
run(self, objective, profiler, printer)

Perform the optimization.

Parameters
  • objective (ObjectiveFunction) – The objective function to optimize.

  • profiler (Profiler) – A profiler to track resource usage.

  • printer (VerbosityPrinter) – printer to use for sending output to stdout.

pygsti.optimize.custom_leastsq(obj_fn, jac_fn, x0, f_norm2_tol=1e-06, jac_norm_tol=1e-06, rel_ftol=1e-06, rel_xtol=1e-06, max_iter=100, num_fd_iters=0, max_dx_scale=1.0, damping_mode='identity', damping_basis='diagonal_values', damping_clip=None, use_acceleration=False, uphill_step_threshold=0.0, init_munu='auto', oob_check_interval=0, oob_action='reject', oob_check_mode=0, resource_alloc=None, arrays_interface=None, serial_solve_proc_threshold=100, x_limits=None, verbosity=0, profiler=None)

An implementation of the Levenberg-Marquardt least-squares optimization algorithm customized for use within pyGSTi.

This general purpose routine mimic to a large extent the interface used by scipy.optimize.leastsq, though it implements a newer (and more robust) version of the algorithm.

Parameters
  • obj_fn (function) – The objective function. Must accept and return 1D numpy ndarrays of length N and M respectively. Same form as scipy.optimize.leastsq.

  • jac_fn (function) – The jacobian function (not optional!). Accepts a 1D array of length N and returns an array of shape (M,N).

  • x0 (numpy.ndarray) – Initial evaluation point.

  • f_norm2_tol (float, optional) – Tolerace for F^2 where F = `norm( sum(obj_fn(x)**2) ) is the least-squares residual. If F**2 < f_norm2_tol, then mark converged.

  • jac_norm_tol (float, optional) – Tolerance for jacobian norm, namely if infn(dot(J.T,f)) < jac_norm_tol then mark converged, where infn is the infinity-norm and f = obj_fn(x).

  • rel_ftol (float, optional) – Tolerance on the relative reduction in F^2, that is, if d(F^2)/F^2 < rel_ftol then mark converged.

  • rel_xtol (float, optional) – Tolerance on the relative value of |x|, so that if d(|x|)/|x| < rel_xtol then mark converged.

  • max_iter (int, optional) – The maximum number of (outer) interations.

  • num_fd_iters (int optional) – Internally compute the Jacobian using a finite-difference method for the first num_fd_iters iterations. This is useful when x0 lies at a special or singular point where the analytic Jacobian is misleading.

  • max_dx_scale (float, optional) – If not None, impose a limit on the magnitude of the step, so that |dx|^2 < max_dx_scale^2 * len(dx) (so elements of dx should be, roughly, less than max_dx_scale).

  • damping_mode ({'identity', 'JTJ', 'invJTJ', 'adaptive'}) – How damping is applied. ‘identity’ means that the damping parameter mu multiplies the identity matrix. ‘JTJ’ means that mu multiplies the diagonal or singular values (depending on scaling_mode) of the JTJ (Fischer information and approx. hessaian) matrix, whereas ‘invJTJ’ means mu multiplies the reciprocals of these values instead. The ‘adaptive’ mode adaptively chooses a damping strategy.

  • damping_basis ({'diagonal_values', 'singular_values'}) – Whether the the diagonal or singular values of the JTJ matrix are used during damping. If ‘singular_values’ is selected, then a SVD of the Jacobian (J) matrix is performed and damping is performed in the basis of (right) singular vectors. If ‘diagonal_values’ is selected, the diagonal values of relevant matrices are used as a proxy for the the singular values (saving the cost of performing a SVD).

  • damping_clip (tuple, optional) – A 2-tuple giving upper and lower bounds for the values that mu multiplies. If damping_mode == “identity” then this argument is ignored, as mu always multiplies a 1.0 on the diagonal if the identity matrix. If None, then no clipping is applied.

  • use_acceleration (bool, optional) – Whether to include a geodesic acceleration term as suggested in arXiv:1201.5885. This is supposed to increase the rate of convergence with very little overhead. In practice we’ve seen mixed results.

  • uphill_step_threshold (float, optional) – Allows uphill steps when taking two consecutive steps in nearly the same direction. The condition for accepting an uphill step is that (uphill_step_threshold-beta)*new_objective < old_objective, where beta is the cosine of the angle between successive steps. If uphill_step_threshold == 0 then no uphill steps are allowed, otherwise it should take a value between 1.0 and 2.0, with 1.0 being the most permissive to uphill steps.

  • init_munu (tuple, optional) – If not None, a (mu, nu) tuple of 2 floats giving the initial values for mu and nu.

  • oob_check_interval (int, optional) – Every oob_check_interval outer iterations, the objective function (obj_fn) is called with a second argument ‘oob_check’, set to True. In this case, obj_fn can raise a ValueError exception to indicate that it is Out Of Bounds. If oob_check_interval is 0 then this check is never performed; if 1 then it is always performed.

  • oob_action ({"reject","stop"}) – What to do when the objective function indicates (by raising a ValueError as described above). “reject” means the step is rejected but the optimization proceeds; “stop” means the optimization stops and returns as converged at the last known-in-bounds point.

  • oob_check_mode (int, optional) – An advanced option, expert use only. If 0 then the optimization is halted as soon as an attempt is made to evaluate the function out of bounds. If 1 then the optimization is halted only when a would-be accepted step is out of bounds.

  • resource_alloc (ResourceAllocation, optional) – When not None, an resource allocation object used for distributing the computation across multiple processors.

  • arrays_interface (ArraysInterface) – An object that provides an interface for creating and manipulating data arrays.

  • serial_solve_proc_threshold (int optional) – When there are fewer than this many processors, the optimizer will solve linear systems serially, using SciPy on a single processor, rather than using a parallelized Gaussian Elimination (with partial pivoting) algorithm coded in Python. Since SciPy’s implementation is more efficient, it’s not worth using the parallel version until there are many processors to spread the work among.

  • x_limits (numpy.ndarray, optional) – A (num_params, 2)-shaped array, holding on each row the (min, max) values for the corresponding parameter (element of the “x” vector). If None, then no limits are imposed.

  • verbosity (int, optional) – Amount of detail to print to stdout.

  • profiler (Profiler, optional) – A profiler object used for to track timing and memory usage.

Returns

  • x (numpy.ndarray) – The optimal solution.

  • converged (bool) – Whether the solution converged.

  • msg (str) – A message indicating why the solution converged (or didn’t).

pygsti.optimize._hack_dx(obj_fn, x, dx, jac, jtj, jtf, f, norm_f)
class pygsti.optimize._UndistributedArraysInterface(num_global_elements, num_global_params)

Bases: ArraysInterface

An arrays interface for the case when the arrays are not actually distributed.

Parameters
  • num_global_elements (int) – The total number of objective function “elements”, i.e. the size of the objective function array f.

  • num_global_params (int) – The total number of (model) parameters, i.e. the size of the x array.

allocate_jtf(self)

Allocate an array for holding a ‘jtf’-type value.

Returns

numpy.ndarray or LocalNumpyArray

allocate_jtj(self)

Allocate an array for holding an approximated Hessian (type ‘jtj’).

Returns

numpy.ndarray or LocalNumpyArray

allocate_jac(self)

Allocate an array for holding a Jacobian matrix (type ‘ep’).

Returns

numpy.ndarray or LocalNumpyArray

deallocate_jtf(self, jtf)

Free an array for holding an objective function value (type ‘jtf’).

Returns

None

deallocate_jtj(self, jtj)

Free an array for holding an approximated Hessian (type ‘jtj’).

Returns

None

deallocate_jac(self, jac)

Free an array for holding a Jacobian matrix (type ‘ep’).

Returns

None

global_num_elements(self)

The total number of objective function “elements”.

This is the size/length of the objective function f vector.

Returns

int

jac_param_slice(self, only_if_leader=False)

The slice into a Jacobian’s columns that belong to this processor.

Parameters

only_if_leader (bool, optional) – If True, the current processor’s parameter slice is ony returned if the processor is the “leader” (i.e. the first) of the processors that calculate the same parameter slice. All non-leader processors return the zero-slice slice(0,0).

Returns

slice

jtf_param_slice(self)

The slice into a ‘jtf’ vector giving the rows of owned by this processor.

Returns

slice

param_fine_info(self)

Returns information regarding how model parameters are distributed among hosts and processors.

This information relates to the “fine” distribution used in distributed layouts, and is needed by some algorithms which utilize shared-memory communication between processors on the same host.

Returns

  • param_fine_slices_by_host (list) – A list with one entry per host. Each entry is itself a list of (rank, (global_param_slice, host_param_slice)) elements where rank is the top-level overall rank of a processor, global_param_slice is the parameter slice that processor owns and host_param_slice is the same slice relative to the parameters owned by the host.

  • owner_host_and_rank_of_global_fine_param_index (dict) – A mapping between parameter indices (keys) and the owning processor rank and host index. Values are (host_index, processor_rank) tuples.

allgather_x(self, x, global_x)

Gather a parameter (x) vector onto all the processors.

Parameters
Returns

None

allscatter_x(self, global_x, x)

Pare down an already-scattered global parameter (x) vector to be just a local x vector.

Parameters
  • global_x (numpy.array or LocalNumpyArray) – The input vector. This global vector is already present on all the processors, so there’s no need to do any MPI communication.

  • x (numpy.array or LocalNumpyArray) – The output vector, typically a slice of global_x..

Returns

None

scatter_x(self, global_x, x)

Scatter a global parameter (x) vector onto all the processors.

Parameters
Returns

None

allgather_f(self, f, global_f)

Gather an objective funtion (f) vector onto all the processors.

Parameters
Returns

None

gather_jtj(self, jtj, return_shared=False)

Gather a Hessian (jtj) matrix onto the root processor.

Parameters
  • jtj (numpy.array or LocalNumpyArray) – The (local) input matrix to gather.

  • return_shared (bool, optional) – Whether the returned array is allowed to be a shared-memory array, which results in a small performance gain because the array used internally to gather the results can be returned directly. When True a shared memory handle is also returned, and the caller assumes responsibilty for freeing the memory via :function:`pygsti.tools.sharedmemtools.cleanup_shared_ndarray`.

Returns

  • gathered_array (numpy.ndarray or None) – The full (global) output array on the root (rank=0) processor and None on all other processors.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – Returned only when return_shared == True. The shared memory handle associated with gathered_array, which is needed to free the memory.

scatter_jtj(self, global_jtj, jtj)

Scatter a Hessian (jtj) matrix onto all the processors.

Parameters
  • global_jtj (numpy.ndarray) – The global Hessian matrix to scatter.

  • jtj (numpy.ndarray or LocalNumpyArray) – The local destination array.

Returns

None

gather_jtf(self, jtf, return_shared=False)

Gather a jtf vector onto the root processor.

Parameters
  • jtf (numpy.array or LocalNumpyArray) – The local input vector to gather.

  • return_shared (bool, optional) – Whether the returned array is allowed to be a shared-memory array, which results in a small performance gain because the array used internally to gather the results can be returned directly. When True a shared memory handle is also returned, and the caller assumes responsibilty for freeing the memory via :function:`pygsti.tools.sharedmemtools.cleanup_shared_ndarray`.

Returns

  • gathered_array (numpy.ndarray or None) – The full (global) output array on the root (rank=0) processor and None on all other processors.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – Returned only when return_shared == True. The shared memory handle associated with gathered_array, which is needed to free the memory.

scatter_jtf(self, global_jtf, jtf)

Scatter a jtf vector onto all the processors.

Parameters
  • global_jtf (numpy.ndarray) – The global vector to scatter.

  • jtf (numpy.ndarray or LocalNumpyArray) – The local destination array.

Returns

None

global_svd_dot(self, jac_v, minus_jtf)

Gathers the dot product between a jtj-type matrix and a jtf-type vector into a global result array.

This is typically used within SVD-defined basis calculations, where jac_v is the “V” matrix of the SVD of a jacobian, and minus_jtf is the negative dot product between the Jacobian matrix and objective function vector.

Parameters
Returns

numpy.ndarray – The global (gathered) parameter vector dot(jac_v.T, minus_jtf).

fill_dx_svd(self, jac_v, global_vec, dx)

Computes the dot product of a jtj-type array with a global parameter array.

The result (dx) is a jtf-type array. This is typically used for computing the x-update vector in the LM method when using a SVD-defined basis.

Parameters
  • jac_v (numpy.ndarray or LocalNumpyArray) – An array of jtj-type.

  • global_vec (numpy.ndarray) – A global parameter vector.

  • dx (numpy.ndarray or LocalNumpyArray) – An array of jtf-type. Filled with dot(jac_v, global_vec) values.

Returns

None

dot_x(self, x1, x2)

Take the dot product of two x-type vectors.

Parameters
Returns

float

norm2_x(self, x)

Compute the Frobenius norm squared of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

infnorm_x(self, x)

Compute the infinity-norm of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

max_x(self, x)

Compute the maximum of an x-type vector.

Parameters

x (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

norm2_f(self, f)

Compute the Frobenius norm squared of an f-type vector.

Parameters

f (numpy.ndarray or LocalNumpyArray) – The vector to operate on.

Returns

float

norm2_jtj(self, jtj)

Compute the Frobenius norm squared of an jtj-type matrix.

Parameters

jtj (numpy.ndarray or LocalNumpyArray) – The array to operate on.

Returns

float

norm2_jac(self, j)

Compute the Frobenius norm squared of an Jacobian matrix (ep-type).

Parameters

j (numpy.ndarray or LocalNumpyArray) – The Jacobian to operate on.

Returns

float

fill_jtf(self, j, f, jtf)

Compute dot(Jacobian.T, f) in supplied memory.

Parameters
  • j (numpy.ndarray or LocalNumpyArray) – Jacobian matrix (type ep).

  • f (numpy.ndarray or LocalNumpyArray) – Objective function vector (type e).

  • jtf (numpy.ndarray or LocalNumpyArray) – Output array, type jtf. Filled with dot(j.T, f) values.

Returns

None

fill_jtj(self, j, jtj, shared_mem_buf=None)

Compute dot(Jacobian.T, Jacobian) in supplied memory.

Parameters
  • j (numpy.ndarray or LocalNumpyArray) – Jacobian matrix (type ep).

  • jtf (numpy.ndarray or LocalNumpyArray) – Output array, type jtj. Filled with dot(j.T, j) values.

  • shared_mem_buf (tuple or None) – Scratch space of shared memory used to speed up repeated calls to fill_jtj. If not none, the value returned from :method:`allocate_jtj_shared_mem_buf`.

Returns

None

allocate_jtj_shared_mem_buf(self)

Allocate scratch space to be used for repeated calls to :method:`fill_jtj`.

Returns

  • scratch (numpy.ndarray or None) – The scratch array.

  • shared_memory_handle (multiprocessing.shared_memory.SharedMemory or None) – The shared memory handle associated with scratch, which is needed to free the memory.

deallocate_jtj_shared_mem_buf(self, jtj_buf)

Frees the scratch memory allocated by :method:`allocate_jtj_shared_mem_buf`.

Parameters

jtj_buf (tuple or None) – The value returned from :method:`allocate_jtj_shared_mem_buf`

jtj_diag_indices(self, jtj)

The indices into a jtj-type array that correspond to diagonal elements of the global matrix.

If jtj were a global quantity, then this would just be numpy.diag_indices_from(jtj), however, it may be more complicated in actuality when different processors hold different sections of the global matrix.

Parameters

jtj (numpy.ndarray or None) – The jtj-type array to get the indices with respect to.

Returns

tuple – A tuple of 1D arrays that can be used to index the elements of jtj that correspond to diagonal elements of the global jtj matrix.

pygsti.optimize._fastcalc
pygsti.optimize.custom_solve(a, b, x, ari, resource_alloc, proc_threshold=100)

Simple parallel Gaussian Elimination with pivoting.

This function was built to provide a parallel alternative to scipy.linalg.solve, and can achieve faster runtimes compared with the serial SciPy routine when the number of available processors and problem size are large enough.

When the number of processors is greater than proc_threshold (below this number the routine just calls scipy.linalg.solve on the root processor) the method works as follows:

  • each processor “owns” some subset of the rows of a and b.

  • iteratively (over pivot columns), the best pivot row is found, and this row is used to eliminate all other elements in the current pivot column. This procedure operations on the joined matrix a|b, and when it completes the matrix a is in reduced row echelon form (RREF).

  • back substitution (trivial because a is in reduced REF) is performed to find the solution x such that a @ x = b.

Parameters
  • a (LocalNumpyArray) – A 2D array with the ‘jtj’ distribution, holding the rows of the a matrix belonging to the current processor. (This belonging is dictated by the “fine” distribution in a distributed layout.)

  • b (LocalNumpyArray) – A 1D array with the ‘jtf’ distribution, holding the rows of the b vector belonging to the current processor.

  • x (LocalNumpyArray) – A 1D array with the ‘jtf’ distribution, holding the rows of the x vector belonging to the current processor. This vector is filled by this function.

  • ari (ArraysInterface) – An object that provides an interface for creating and manipulating data arrays.

  • resource_alloc (ResourceAllocation) – Gives the resources (e.g., processors and memory) available for use.

  • proc_threshold (int, optional) – Below this number of processors this routine will simply gather a and b to a single (the rank 0) processor, call SciPy’s serial linear solver, scipy.linalg.solve, and scatter the results back onto all the processors.

Returns

None

pygsti.optimize._find_pivot(a, b, icol, potential_pivot_inds, my_row_slice, shared_floats, shared_ints, resource_alloc, comm, host_comm, buf1, buf2, buf3, best_host_indices, best_host_vals)
pygsti.optimize._broadcast_pivot_row(a, b, ibest_local, h, k, shared_rowb, local_pivot_rowb, potential_pivot_mask, resource_alloc, comm, host_comm)
pygsti.optimize._update_rows(a, b, icol, ipivot_local, pivot_row, pivot_b)
pygsti.optimize._back_substitution(a, b, x, pivot_row_indices, my_row_slice, ari, resource_alloc, host_comm)
pygsti.optimize._tallskinny_custom_solve(a, b, resource_alloc)

Note

Based on “Parallel QR algorithm for data-driven decompositions” by Sayadi et al. (Center for Turbulence Research 335 Proceedings of the Summer Program 2014)

pygsti.optimize.fmax_cg(f, x0, maxiters=100, tol=1e-08, dfdx_and_bdflag=None, xopt=None)

Custom conjugate-gradient (CG) routine for maximizing a function.

This function runs slower than scipy.optimize’s ‘CG’ method, but doesn’t give up or get stuck as easily, and so sometimes can be a better option.

Parameters
  • f (function) – The function to optimize

  • x0 (numpy array) – The starting point (argument to fn).

  • maxiters (int, optional) – Maximum iterations.

  • tol (float, optional) – Tolerace for convergence (compared to absolute difference in f)

  • dfdx_and_bdflag (function, optional) – Function to compute jacobian of f as well as a boundary-flag.

  • xopt (numpy array, optional) – Used for debugging, output can be printed relating current optimum relative xopt, assumed to be a known good optimum.

Returns

scipy.optimize.Result object – Includes members ‘x’, ‘fun’, ‘success’, and ‘message’. Note: returns the negated maximum in ‘fun’ in order to conform to the return value of other minimization routines.

class pygsti.optimize._VerbosityPrinter(verbosity=1, filename=None, comm=None, warnings=True, split=False, clear_file=True)

Bases: object

Class responsible for logging things to stdout or a file.

Controls verbosity and can print progress bars. ex:

>>> VerbosityPrinter(1)

would construct a printer that printed out messages of level one or higher to the screen.

>>> VerbosityPrinter(3, 'output.txt')

would construct a printer that sends verbose output to a text file

The static function create_printer() will construct a printer from either an integer or an already existing printer. it is a static method of the VerbosityPrinter class, so it is called like so:

>>> VerbosityPrinter.create_printer(2)

or

>>> VerbostityPrinter.create_printer(VerbosityPrinter(3, 'output.txt'))

printer.log('status') would log ‘status’ if the printers verbosity was one or higher. printer.log('status2', 2) would log ‘status2’ if the printer’s verbosity was two or higher

printer.error('something terrible happened') would ALWAYS log ‘something terrible happened’. printer.warning('something worrisome happened') would log if verbosity was one or higher - the same as a normal status.

Both printer.error and printer.warning will prepend ‘ERROR: ‘ or ‘WARNING: ‘ to the message they are given. Optionally, printer.log() can also prepend ‘Status_n’ to the message, where n is the message level.

Logging of progress bars/iterations:

>>> with printer_instance.progress_logging(verbosity):
>>>     for i, item in enumerate(data):
>>>         printer.show_progress(i, len(data))
>>>         printer.log(...)

will output either a progress bar or iteration statuses depending on the printer’s verbosity

Parameters
  • verbosity (int) – How verbose the printer should be.

  • filename (str, optional) – Where to put output (If none, output goes to screen)

  • comm (mpi4py.MPI.Comm or ResourceAllocation, optional) – Restricts output if the program is running in parallel (By default, if the rank is 0, output is sent to screen, and otherwise sent to commfiles 1, 2, …

  • warnings (bool, optional) – Whether or not to print warnings

  • split (bool, optional) – Whether to split output between stdout and stderr as appropriate, or to combine the streams so everything is sent to stdout.

  • clear_file (bool, optional) – Whether or not filename should be cleared (overwritten) or simply appended to.

_comm_path

relative path where comm files (outputs of non-root ranks) are stored.

Type

str

_comm_file_name

root filename for comm files (outputs of non-root ranks).

Type

str

_comm_file_ext

filename extension for comm files (outputs of non-root ranks).

Type

str

_comm_path =
_comm_file_name =
_comm_file_ext = .txt
_create_file(self, filename)
_get_comm_file(self, comm_id)
clone(self)

Instead of deepcopy, initialize a new printer object and feed it some select deepcopied members

Returns

VerbosityPrinter

static create_printer(verbosity, comm=None)

Function for converting between interfaces

Parameters
  • verbosity (int or VerbosityPrinter object, required:) – object to build a printer from

  • comm (mpi4py.MPI.Comm object, optional) – Comm object to build printers with. !Will override!

Returns

VerbosityPrinter – The printer object, constructed from either an integer or another printer

__add__(self, other)

Increase the verbosity of a VerbosityPrinter

__sub__(self, other)

Decrease the verbosity of a VerbosityPrinter

__getstate__(self)
__setstate__(self, state_dict)
_append_to(self, filename, message)
_put(self, message, flush=True, stderr=False)
_record(self, typ, level, message)
error(self, message)

Log an error to the screen/file

Parameters

message (str) – the error message

Returns

None

warning(self, message)

Log a warning to the screen/file if verbosity > 1

Parameters

message (str) – the warning message

Returns

None

log(self, message, message_level=None, indent_char='  ', show_statustype=False, do_indent=True, indent_offset=0, end='\n', flush=True)

Log a status message to screen/file.

Determines whether the message should be printed based on current verbosity setting, then sends the message to the appropriate output

Parameters
  • message (str) – the message to print (or log)

  • message_level (int, optional) – the minimum verbosity level at which this level is printed.

  • indent_char (str, optional) – what constitutes an “indent” (messages at higher levels are indented more when do_indent=True).

  • show_statustype (bool, optional) – if True, prepend lines with “Status Level X” indicating the message_level.

  • do_indent (bool, optional) – whether messages at higher message levels should be indented. Note that if this is False it may be helpful to set show_statustype=True.

  • indent_offset (int, optional) – an additional number of indentations to add, on top of any due to the message level.

  • end (str, optional) – the character (or string) to end message lines with.

  • flush (bool, optional) – whether stdout should be flushed right after this message is printed (this avoids delays in on-screen output due to buffering).

Returns

None

_progress_bar(self, iteration, total, bar_length, num_decimals, fill_char, empty_char, prefix, suffix, indent)
_verbose_iteration(self, iteration, total, prefix, suffix, verbose_messages, indent, end)
__str__(self)

Return str(self).

verbosity_env(self, level)

Create a temporary environment with a different verbosity level.

This is context manager, controlled using Python’s with statement:

>>> with printer.verbosity_env(2):
        printer.log('Message1') # printed at verbosity level 2
        printer.log('Message2') # printed at verbosity level 2
Parameters

level (int) – the verbosity level of the environment.

progress_logging(self, message_level=1)

Context manager for logging progress bars/iterations.

(The printer will return to its normal, unrestricted state when the progress logging has finished)

Parameters

message_level (int, optional) – progress messages will not be shown until the verbosity level reaches message_level.

show_progress(self, iteration, total, bar_length=50, num_decimals=2, fill_char='#', empty_char='-', prefix='Progress:', suffix='', verbose_messages=[], indent_char='  ', end='\n')

Displays a progress message (to be used within a progress_logging block).

Parameters
  • iteration (int) – the 0-based current iteration – the interation number this message is for.

  • total (int) – the total number of iterations expected.

  • bar_length (int, optional) – the length, in characters, of a text-format progress bar (only used when the verbosity level is exactly equal to the progress_logging message level.

  • num_decimals (int, optional) – number of places after the decimal point that are displayed in progress bar’s percentage complete.

  • fill_char (str, optional) – replaces ‘#’ as the bar-filling character

  • empty_char (str, optional) – replaces ‘-’ as the empty-bar character

  • prefix (str, optional) – message in front of the bar

  • suffix (str, optional) – message after the bar

  • verbose_messages (list, optional) – A list of strings to display after an initial “Iter X of Y” line when the verbosity level is higher than the progress_logging message level and so more verbose messages are shown (and a progress bar is not). The elements of verbose_messages will occur, one per line, after the initial “Iter X of Y” line.

  • indent_char (str, optional) – what constitutes an “indentation”.

  • end (str, optional) – the character (or string) to end message lines with.

Returns

None

_end_progress(self)
start_recording(self)

Begins recording the output (to memory).

Begins recording (in memory) a list of (type, verbosityLevel, message) tuples that is returned by the next call to :method:`stop_recording`.

Returns

None

is_recording(self)

Returns whether this VerbosityPrinter is currently recording.

Returns

bool

stop_recording(self)

Stops recording and returns recorded output.

Stops a “recording” started by :method:`start_recording` and returns the list of (type, verbosityLevel, message) tuples that have been recorded since then.

Returns

list

pygsti.optimize.minimize(fn, x0, method='cg', callback=None, tol=1e-10, maxiter=1000000, maxfev=None, stopval=None, jac=None, verbosity=0, **addl_kwargs)

Minimizes the function fn starting at x0.

This is a gateway function to all other minimization routines within this module, providing a common interface to many different minimization methods (including and extending beyond those available from scipy.optimize).

Parameters
  • fn (function) – The function to minimize.

  • x0 (numpy array) – The starting point (argument to fn).

  • method (string, optional) – Which minimization method to use. Allowed values are: “simplex” : uses _fmin_simplex “supersimplex” : uses _fmin_supersimplex “customcg” : uses fmax_cg (custom CG method) “brute” : uses scipy.optimize.brute “basinhopping” : uses scipy.optimize.basinhopping with L-BFGS-B “swarm” : uses _fmin_particle_swarm “evolve” : uses _fmin_evolutionary (which uses DEAP) < methods available from scipy.optimize.minimize >

  • callback (function, optional) – A callback function to be called in order to track optimizer progress. Should have signature: myCallback(x, f=None, accepted=None). Note that create_objfn_printer(…) function can be used to create a callback.

  • tol (float, optional) – Tolerance value used for all types of tolerances available in a given method.

  • maxiter (int, optional) – Maximum iterations.

  • maxfev (int, optional) – Maximum function evaluations; used only when available, and defaults to maxiter.

  • stopval (float, optional) – For basinhopping method only. When f <= stopval then basinhopping outer loop will terminate. Useful when a bound on the minimum is known.

  • jac (function) – Jacobian function.

  • verbosity (int) – Level of detail to print to stdout.

  • addl_kwargs (dict) – Additional arguments for the specific optimizer being used.

Returns

scipy.optimize.Result object – Includes members ‘x’, ‘fun’, ‘success’, and ‘message’.

pygsti.optimize._fmin_supersimplex(fn, x0, abs_outer_tol, rel_outer_tol, inner_tol, max_outer_iter, min_inner_maxiter, max_inner_maxiter, callback, printer)

Minimize a function using repeated applications of the simplex algorithm.

By varying the maximum number of iterations and repeatedly calling scipy’s Nelder-Mead simplex optimization, this function performs as a robust (but slow) minimization.

Parameters
  • fn (function) – The function to minimize.

  • x0 (numpy array) – The starting point (argument to fn).

  • abs_outer_tol (float) – Absolute tolerance of outer loop

  • rel_outer_tol (float) – Relative tolerance of outer loop

  • inner_tol (float) – Tolerance fo inner loop

  • max_outer_iter (int) – Maximum number of outer-loop iterations

  • min_inner_maxiter (int) – Minimum number of inner-loop iterations

  • max_inner_maxiter (int) – Maxium number of outer-loop iterations

  • printer (VerbosityPrinter) – Printer for displaying output status messages.

Returns

scipy.optimize.Result object – Includes members ‘x’, ‘fun’, ‘success’, and ‘message’.

pygsti.optimize._fmin_simplex(fn, x0, slide=1.0, tol=1e-08, maxiter=1000)

Minimizes a function using a custom simplex implmentation.

This was used primarily to check scipy’s Nelder-Mead method and runs much slower, so there’s not much reason for using this method.

Parameters
  • fn (function) – The function to minimize.

  • x0 (numpy array) – The starting point (argument to fn).

  • slide (float, optional) – Affects initial simplex point locations

  • tol (float, optional) – Relative tolerance as a convergence criterion.

  • maxiter (int, optional) – Maximum iterations.

Returns

scipy.optimize.Result object – Includes members ‘x’, ‘fun’, ‘success’, and ‘message’.

pygsti.optimize._fmin_particle_swarm(f, x0, err_crit, iter_max, printer, popsize=100, c1=2, c2=2)

A simple implementation of the Particle Swarm Optimization Algorithm.

(Pradeep Gowda 2009-03-16)

Parameters
  • f (function) – The function to minimize.

  • x0 (numpy array) – The starting point (argument to fn).

  • err_crit (float) – Critical error (i.e. tolerance). Stops when error < err_crit.

  • iter_max (int) – Maximum iterations.

  • popsize (int, optional) – Population size. Larger populations are better at finding the global optimum but make the algorithm take longer to run.

  • c1 (float, optional) – Coefficient describing a particle’s affinity for it’s (local) maximum.

  • c2 (float, optional) – Coefficient describing a particle’s affinity for the best maximum any particle has seen (the current global max).

Returns

scipy.optimize.Result object – Includes members ‘x’, ‘fun’, ‘success’, and ‘message’.

pygsti.optimize._fmin_evolutionary(f, x0, num_generations, num_individuals, printer)

Minimize a function using an evolutionary algorithm.

Uses python’s deap package to perform an evolutionary algorithm to find a function’s global minimum.

Parameters
  • f (function) – The function to minimize.

  • x0 (numpy array) – The starting point (argument to fn).

  • num_generations (int) – The number of generations to carry out. (similar to the number of iterations)

  • num_individuals (int) – The number of individuals in each generation. More individuals make finding the global optimum more likely, but take longer to run.

Returns

scipy.optimize.Result object – Includes members ‘x’, ‘fun’, ‘success’, and ‘message’.

pygsti.optimize.create_objfn_printer(obj_func, start_time=None)

Create a callback function that prints the value of an objective function.

Parameters
  • obj_func (function) – The objective function to print.

  • start_time (float , optional) – A reference starting time to use when printing elapsed times. If None, then the system time when this function is called is used (which is often what you want).

Returns

function – A callback function which prints obj_func.

pygsti.optimize._fwd_diff_jacobian(f, x0, eps=1e-10)
pygsti.optimize.check_jac(f, x0, jac_to_check, eps=1e-10, tol=1e-06, err_type='rel', verbosity=1)

Checks a jacobian function using finite differences.

Parameters
  • f (function) – The function to check.

  • x0 (numpy array) – The point at which to check the jacobian.

  • jac_to_check (function) – A function which should compute the jacobian of f at x0.

  • eps (float, optional) – Epsilon to use in finite difference calculations of jacobian.

  • tol (float, optional) – The allowd tolerance on the relative differene between the values of the finite difference and jac_to_check jacobians if err_type == ‘rel’ or the absolute difference if err_type == ‘abs’.

  • err_type ({'rel', 'abs'), optional) – How to interpret tol (see above).

  • verbosity (int, optional) – Controls how much detail is printed to stdout.

Returns

  • errSum (float) – The total error between the jacobians.

  • errs (list) – List of (row,col,err) tuples giving the error for each row and column.

  • ffd_jac (numpy array) – The computed forward-finite-difference jacobian.

pygsti.optimize._update_circuit_probs(probs, freqs, circuit_budget)
pygsti.optimize._minimize(fn, x0, method='cg', callback=None, tol=1e-10, maxiter=1000000, maxfev=None, stopval=None, jac=None, verbosity=0, **addl_kwargs)

Minimizes the function fn starting at x0.

This is a gateway function to all other minimization routines within this module, providing a common interface to many different minimization methods (including and extending beyond those available from scipy.optimize).

Parameters
  • fn (function) – The function to minimize.

  • x0 (numpy array) – The starting point (argument to fn).

  • method (string, optional) – Which minimization method to use. Allowed values are: “simplex” : uses _fmin_simplex “supersimplex” : uses _fmin_supersimplex “customcg” : uses fmax_cg (custom CG method) “brute” : uses scipy.optimize.brute “basinhopping” : uses scipy.optimize.basinhopping with L-BFGS-B “swarm” : uses _fmin_particle_swarm “evolve” : uses _fmin_evolutionary (which uses DEAP) < methods available from scipy.optimize.minimize >

  • callback (function, optional) – A callback function to be called in order to track optimizer progress. Should have signature: myCallback(x, f=None, accepted=None). Note that create_objfn_printer(…) function can be used to create a callback.

  • tol (float, optional) – Tolerance value used for all types of tolerances available in a given method.

  • maxiter (int, optional) – Maximum iterations.

  • maxfev (int, optional) – Maximum function evaluations; used only when available, and defaults to maxiter.

  • stopval (float, optional) – For basinhopping method only. When f <= stopval then basinhopping outer loop will terminate. Useful when a bound on the minimum is known.

  • jac (function) – Jacobian function.

  • verbosity (int) – Level of detail to print to stdout.

  • addl_kwargs (dict) – Additional arguments for the specific optimizer being used.

Returns

scipy.optimize.Result object – Includes members ‘x’, ‘fun’, ‘success’, and ‘message’.

pygsti.optimize.optimize_wildcard_budget_neldermead(budget, L1weights, wildcard_objfn, two_dlogl_threshold, redbox_threshold, printer, smart_init=True, max_outer_iters=10, initial_eta=10.0)

Uses repeated Nelder-Mead to optimize the wildcard budget. Includes both aggregate and per-circuit constraints.

pygsti.optimize.optimize_wildcard_budget_percircuit_only_cvxpy(budget, L1weights, objfn, redbox_threshold, printer)

Uses CVXPY to optimize the wildcard budget. Includes only per-circuit constraints.

pygsti.optimize._get_critical_circuit_budgets(objfn, redbox_threshold)
pygsti.optimize._agg_dlogl(current_probs, objfn, two_dlogl_threshold)
pygsti.optimize._agg_dlogl_deriv(current_probs, objfn, percircuit_budget_deriv, probs_deriv_wrt_percircuit_budget)
pygsti.optimize._agg_dlogl_hessian(current_probs, objfn, percircuit_budget_deriv, probs_deriv_wrt_percircuit_budget)
pygsti.optimize._proxy_agg_dlogl(x, tvds, fn0s, percircuit_budget_deriv, two_dlogl_threshold)
pygsti.optimize._proxy_agg_dlogl_deriv(x, tvds, fn0s, percircuit_budget_deriv)
pygsti.optimize._proxy_agg_dlogl_hessian(x, tvds, fn0s, percircuit_budget_deriv)
pygsti.optimize.optimize_wildcard_budget_cvxopt(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, abs_tol=1e-05, rel_tol=1e-05, max_iters=50)

Uses CVXOPT to optimize the wildcard budget. Includes both aggregate and per-circuit constraints.

pygsti.optimize.optimize_wildcard_budget_cvxopt_zeroreg(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, abs_tol=1e-05, rel_tol=1e-05, max_iters=50, small=1e-06)

Adds regularization of the L1 term around zero values of the budget. This doesn’t seem to help much.

pygsti.optimize.optimize_wildcard_budget_barrier(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, tol=1e-07, max_iters=50, num_steps=3, save_debugplot_data=False)

Uses a barrier method (for convex optimization) to optimize the wildcard budget. Includes both aggregate and per-circuit constraints.

pygsti.optimize.NewtonSolve(initial_x, fn, fn_with_derivs=None, dx_tol=1e-06, max_iters=20, printer=None, lmbda=0.0)
pygsti.optimize.optimize_wildcard_budget_cvxopt_smoothed(budget, L1weights, objfn, two_dlogl_threshold, redbox_threshold, printer, abs_tol=1e-05, rel_tol=1e-05, max_iters=50)

Uses a smooted version of the objective function. Doesn’t seem to help much.

The thinking here was to eliminate the 2nd derivative discontinuities of the original problem.

pygsti.optimize._compute_fd(x, fn, compute_hessian=True, eps=1e-07)