From 26c682f34e9222a0def9fad9f5d653d338023192 Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Tue, 28 May 2024 12:14:40 -0400 Subject: [PATCH] progress --- pygsti/algorithms/randomcircuit.py | 192 --------- pygsti/baseobjs/basis.py | 3 +- pygsti/evotypes/qibo/effectreps.py | 2 +- pygsti/extras/drift/stabilityanalyzer.py | 4 +- pygsti/io/legacyio.py | 385 ------------------ .../modelmembers/operations/affineshiftop.py | 1 + pygsti/modelmembers/operations/eigpdenseop.py | 4 +- .../operations/fullarbitraryop.py | 1 + pygsti/modelmembers/operations/fulltpop.py | 2 +- .../modelmembers/operations/fullunitaryop.py | 3 +- pygsti/modelmembers/povms/__init__.py | 6 +- .../modelmembers/states/computationalstate.py | 4 +- pygsti/modelmembers/states/state.py | 2 +- pygsti/models/explicitcalc.py | 6 +- pygsti/models/modelconstruction.py | 2 +- pygsti/protocols/confidenceregionfactory.py | 12 +- pygsti/report/mpl_colormaps.py | 2 +- pygsti/report/plothelpers.py | 4 +- pygsti/report/reportables.py | 8 +- pygsti/report/workspaceplots.py | 8 +- 20 files changed, 39 insertions(+), 612 deletions(-) delete mode 100644 pygsti/io/legacyio.py diff --git a/pygsti/algorithms/randomcircuit.py b/pygsti/algorithms/randomcircuit.py index c45f1d76c..8cd504f48 100644 --- a/pygsti/algorithms/randomcircuit.py +++ b/pygsti/algorithms/randomcircuit.py @@ -2620,198 +2620,6 @@ def create_mirror_rb_circuit(pspec, absolute_compilation, length, qubit_labels=N return circuit, idealout -#### Commented out as most of this functionality can be found elsewhere and this code has not been tested recently. -# def sample_one_q_generalized_rb_circuit(m, group_or_model, inverse=True, random_pauli=False, interleaved=None, -# group_inverse_only=False, group_prep=False, compilation=None, -# generated_group=None, model_to_group_labels=None, seed=None, rand_state=None): -# """ -# Makes a random 1-qubit RB circuit, with RB over an arbitrary group. - -# This function also contains a range of other options that allow circuits for many -# types of RB to be generated, including: - -# - Clifford RB -# - Direct RB -# - Interleaved Clifford or direct RB -# - Unitarity Clifford or direct RB - -# The function can in-principle be used beyond 1-qubit RB, but it relies on explicit matrix representation -# of a group, which is infeasble for, e.g., the many-qubit Clifford group. - -# Note that this function has *not* been carefully tested. This will be rectified in the future, -# or this function will be replaced. - -# Parameters -# ---------- -# m : int -# The number of random gates in the circuit. - -# group_or_model : Model or MatrixGroup -# Which Model of MatrixGroup to create the random circuit for. If -# inverse is true and this is a Model, the Model gates must form -# a group (so in this case it requires the *target model* rather than -# a noisy model). When inverse is true, the MatrixGroup for the model -# is generated. Therefore, if inverse is true and the function is called -# multiple times, it will be much faster if the MatrixGroup is provided. - -# inverse : Bool, optional -# If true, the random circuit is followed by its inverse gate. The model -# must form a group if this is true. If it is true then the circuit -# returned is length m+1 (2m+1) if interleaved is False (True). - -# random_pauli : , optional -# - -# interleaved : Str, optional -# If not None, then a oplabel string. When a oplabel string is provided, -# every random gate is followed by this gate. So the returned circuit is of -# length 2m+1 (2m) if inverse is True (False). - -# group_inverse_only : , optional -# - -# group_prep : bool, optional -# If group_inverse_only is True and inverse is True, setting this to true -# creates a "group pre-twirl". Does nothing otherwise (which should be changed -# at some point). - -# compilation : , optional -# - -# generated_group : , optional -# - -# model_to_group_labels : , optional -# - -# seed : int, optional -# Seed for random number generator; optional. - -# rand_state : numpy.random.RandomState, optional -# A RandomState object to generate samples from. Can be useful to set -# instead of `seed` if you want reproducible distribution samples across -# multiple random function calls but you don't want to bother with -# manually incrementing seeds between those calls. - -# Returns -# ------- -# Circuit -# The random circuit of length: -# m if inverse = False, interleaved = None -# m + 1 if inverse = True, interleaved = None -# 2m if inverse = False, interleaved not None -# 2m + 1 if inverse = True, interleaved not None -# """ -# assert hasattr(group_or_model, 'gates') or hasattr(group_or_model, -# 'product'), 'group_or_model must be a MatrixGroup of Model' -# group = None -# model = None -# if hasattr(group_or_model, 'gates'): -# model = group_or_model -# if hasattr(group_or_model, 'product'): -# group = group_or_model - -# if rand_state is None: -# rndm = _np.random.RandomState(seed) # ok if seed is None -# else: -# rndm = rand_state - -# if (inverse) and (not group_inverse_only): -# if model: -# group = _rbobjs.MatrixGroup(group_or_model.operations.values(), -# group_or_model.operations.keys()) - -# rndm_indices = rndm.randint(0, len(group), m) -# if interleaved: -# interleaved_index = group.label_indices[interleaved] -# interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64) -# interleaved_indices[:, 0] = rndm_indices -# rndm_indices = interleaved_indices.flatten() - -# random_string = [group.labels[i] for i in rndm_indices] -# effective_op = group.product(random_string) -# inv = group.inverse_index(effective_op) -# random_string.append(inv) - -# if (inverse) and (group_inverse_only): -# assert (model is not None), "gateset_or_group should be a Model!" -# assert (compilation is not None), "Compilation of group elements to model needs to be specified!" -# assert (generated_group is not None), "Generated group needs to be specified!" -# if model_to_group_labels is None: -# model_to_group_labels = {} -# for gate in model.primitive_op_labels: -# assert(gate in generated_group.labels), "model labels are not in \ -# the generated group! Specify a model_to_group_labels dictionary." -# model_to_group_labels = {'gate': 'gate'} -# else: -# for gate in model.primitive_op_labels: -# assert(gate in model_to_group_labels.keys()), "model to group labels \ -# are invalid!" -# assert(model_to_group_labels[gate] in generated_group.labels), "model to group labels \ -# are invalid!" - -# opLabels = model.primitive_op_labels -# rndm_indices = rndm.randint(0, len(opLabels), m) -# if interleaved: -# interleaved_index = opLabels.index(interleaved) -# interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64) -# interleaved_indices[:, 0] = rndm_indices -# rndm_indices = interleaved_indices.flatten() - -# # This bit of code is a quick hashed job. Needs to be checked at somepoint -# if group_prep: -# rndm_group_index = rndm.randint(0, len(generated_group)) -# prep_random_string = compilation[generated_group.labels[rndm_group_index]] -# prep_random_string_group = [generated_group.labels[rndm_group_index], ] - -# random_string = [opLabels[i] for i in rndm_indices] -# random_string_group = [model_to_group_labels[opLabels[i]] for i in rndm_indices] -# # This bit of code is a quick hashed job. Needs to be checked at somepoint -# if group_prep: -# random_string = prep_random_string + random_string -# random_string_group = prep_random_string_group + random_string_group -# #print(random_string) -# inversion_group_element = generated_group.inverse_index(generated_group.product(random_string_group)) - -# # This bit of code is a quick hash job, and only works when the group is the 1-qubit Cliffords -# if random_pauli: -# pauli_keys = ['Gc0', 'Gc3', 'Gc6', 'Gc9'] -# rndm_index = rndm.randint(0, 4) - -# if rndm_index == 0 or rndm_index == 3: -# bitflip = False -# else: -# bitflip = True -# inversion_group_element = generated_group.product([inversion_group_element, pauli_keys[rndm_index]]) - -# inversion_sequence = compilation[inversion_group_element] -# random_string.extend(inversion_sequence) - -# if not inverse: -# if model: -# opLabels = model.primitive_op_labels -# rndm_indices = rndm.randint(0, len(opLabels), m) -# if interleaved: -# interleaved_index = opLabels.index(interleaved) -# interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64) -# interleaved_indices[:, 0] = rndm_indices -# rndm_indices = interleaved_indices.flatten() -# random_string = [opLabels[i] for i in rndm_indices] - -# else: -# rndm_indices = rndm.randint(0, len(group), m) -# if interleaved: -# interleaved_index = group.label_indices[interleaved] -# interleaved_indices = interleaved_index * _np.ones((m, 2), _np.int64) -# interleaved_indices[:, 0] = rndm_indices -# rndm_indices = interleaved_indices.flatten() -# random_string = [group.labels[i] for i in rndm_indices] - -# if not random_pauli: -# return _cir.Circuit(random_string) -# if random_pauli: -# return _cir.Circuit(random_string), bitflip - def create_random_germ(pspec, depths, interacting_qs_density, qubit_labels, rand_state=None): """ diff --git a/pygsti/baseobjs/basis.py b/pygsti/baseobjs/basis.py index 2505cf06e..f4b329e7a 100644 --- a/pygsti/baseobjs/basis.py +++ b/pygsti/baseobjs/basis.py @@ -387,6 +387,7 @@ def vector_elements(self): if self.sparse: return [_sps.lil_matrix(el).reshape((self.elsize, 1)) for el in self.elements] else: + # Use flatten (rather than ravel) to ensure a copy is made. return [el.flatten() for el in self.elements] def copy(self): @@ -1468,7 +1469,7 @@ def to_elementstd_transform_matrix(self): if self.sparse: vel = _sps.lil_matrix(el.reshape(-1, 1)) # sparse vector == sparse n x 1 matrix else: - vel = el.flatten() + vel = el.ravel() toSimpleStd[:, i] = vel return toSimpleStd diff --git a/pygsti/evotypes/qibo/effectreps.py b/pygsti/evotypes/qibo/effectreps.py index 5a350d9d6..dac57e1b5 100644 --- a/pygsti/evotypes/qibo/effectreps.py +++ b/pygsti/evotypes/qibo/effectreps.py @@ -52,7 +52,7 @@ def probability(self, state): qibo_circuit = state.qibo_circuit results = qibo_circuit(initial_state) - return _np.real_if_close(_np.dot(effect_state.flatten().conjugate(), results.state().flatten())) + return _np.real_if_close(effect_state.ravel().conjugate() @ results.state().ravel()) def to_dense(self, on_space): return self.state_rep.to_dense(on_space) diff --git a/pygsti/extras/drift/stabilityanalyzer.py b/pygsti/extras/drift/stabilityanalyzer.py index e139be726..fe315387b 100644 --- a/pygsti/extras/drift/stabilityanalyzer.py +++ b/pygsti/extras/drift/stabilityanalyzer.py @@ -1235,9 +1235,11 @@ def run_instability_detection(self, significance=0.05, freqstest=None, tests='au # If we're not testing a single spectrum we need to flatten the >1D array. if len(_np.shape(spectra)) > 1: + # Use flatten (rather than ravel) to ensure a copy is made. powerlist = spectra[indices].flatten() # If we're testing a single spectrum, we can just copy the 1D array. - else: powerlist = spectra[indices].copy() + else: + powerlist = spectra[indices].copy() # The indices that will go with the elements in the flattened spectra. powerindices = [tup for tup in _itertools.product(*iterBenjHoch)] diff --git a/pygsti/io/legacyio.py b/pygsti/io/legacyio.py deleted file mode 100644 index 9f105e8e6..000000000 --- a/pygsti/io/legacyio.py +++ /dev/null @@ -1,385 +0,0 @@ -""" -Functions for allowing old-vesion objects to unpickle load. -""" -#*************************************************************************************************** -# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). -# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights -# in this software. -# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except -# in compliance with the License. You may obtain a copy of the License at -# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory. -#*************************************************************************************************** - - -#These functions no longer work, and the changes have become too great to retain -# backward compatibility with old versions. Keep this commented code around -# for potentially adding similar functionality in future versions. -# -#import numbers as _numbers -#import sys as _sys -#from contextlib import contextmanager as _contextmanager -#from types import ModuleType as _ModuleType -# -#from .. import objects as _objs -#from .. import circuits as _circuits -#from ..circuits import circuit as _circuit -#from ..objects.replib import slowreplib as _slow -# -# -#@_contextmanager -#def enable_no_cython_unpickling(): -# """ -# Context manager for unpickling objects constructed *with* Cython extensions. -# -# A context manager enabling the un-pickling of pyGSTi objects that -# were constructed on a system *with* pyGSTi's C-extensions, when the -# current system's pyGSTi does not have these extensions. -# """ -# -# class dummy_DMStateRep(object): -# def __new__(cls, data, reducefix): -# #replacement_obj = _slow.DMStateRep.__new__(_slow.DMStateRep) -# replacement_obj = _slow.DMStateRep(data, reducefix) -# return replacement_obj -# -# class dummy_DMEffectRepDense(object): -# def __new__(cls, data, reducefix): -# #replacement_obj = _slow.DMEffectRepDense.__new__(_slow.DMEffectRepDense) -# replacement_obj = _slow.DMEffectRepDense(data, reducefix) -# return replacement_obj -# -# class dummy_DMOpRepDense(object): -# def __new__(cls, data, reducefix): -# #replacement_obj = _slow.DMOpRepDense.__new__(_slow.DMEffectRepDense) -# replacement_obj = _slow.DMOpRepDense(data, reducefix) -# return replacement_obj -# -# assert(_sys.modules.get('pygsti.objects.replib.fastreplib', None) is None), \ -# "You should only use this function when they Cython extensions are *not* built!" -# fastreplib = _ModuleType("fastreplib") -# fastreplib.DMStateRep = dummy_DMStateRep -# fastreplib.DMEffectRepDense = dummy_DMEffectRepDense -# fastreplib.DMOpRepDense = dummy_DMOpRepDense -# _sys.modules['pygsti.objects.replib.fastreplib'] = fastreplib -# -# yield -# -# del _sys.modules['pygsti.objects.replib.fastreplib'] -# -# -#@_contextmanager -#def enable_old_object_unpickling(old_version="0.9.6"): -# """ -# Context manager enabling unpickling of old-verion objects. -# -# Returns a context manager which enables the unpickling of old-version ( -# back to 0.9.6 and sometimes prior) objects. -# -# Parameters -# ---------- -# old_version : str, optional -# The string representation of the old version whose pickle files you'd -# like to unpickle. E.g., `"0.9.7"` -# """ -# def totup(v): return tuple(map(int, v.split('.'))) -# old_version = totup(old_version) -# -# if old_version < totup("0.9.6"): -# raise ValueError(("Cannot unpickle files from version < 0.9.6 with this version." -# " Revert back to 0.9.6 and update to 0.9.6 first.")) -# -# if old_version == totup("0.9.6"): -# class dummy_GateString(object): -# def __new__(cls): -# replacement_obj = _circuit.Circuit.__new__(_circuit.Circuit) -# return replacement_obj -# -# def GateString_setstate(self, state): -# s = state['_str'] if '_str' in state else state['str'] -# c = _objs.Circuit(state['_tup'], stringrep=s) -# #OLD: self.__dict__.update(c.__dict__) -# return c.__dict__ # now just return updated Circuit state -# -# class dummy_CompressedGateString(object): -# def __new__(cls): -# replacement_obj = _circuit.CompressedCircuit.__new__(_circuit.CompressedCircuit) -# return replacement_obj -# -# class dummy_GateSet(object): -# def __new__(cls): -# replacement_obj = _objs.ExplicitOpModel.__new__(_objs.ExplicitOpModel) -# return replacement_obj -# -# class dummy_GateMatrixCalc(object): -# def __new__(cls): -# replacement_obj = _objs.MatrixForwardSimulator.__new__(_objs.MatrixForwardSimulator) -# return replacement_obj -# -# class dummy_AutoGator(object): pass -# class dummy_SimpleCompositionAutoGator(object): pass -# -# class dummy_LindbladParameterizedGate(object): -# def __new__(cls): -# replacement_obj = _objs.LindbladDenseOp.__new__(_objs.LindbladDenseOp) -# return replacement_obj -# -# def Lind_setstate(self, state): -# assert(not state['sparse']), "Can only unpickle old *dense* LindbladParameterizedGate objects" -# g = _objs.LindbladDenseOp.from_operation_matrix(state['base'], state['unitary_postfactor'], -# ham_basis=state['ham_basis'], -# nonham_basis=state['other_basis'], -# param_mode=state['param_mode'], -# nonham_mode=state['nonham_mode'], truncate=True, -# mx_basis=state['matrix_basis'], evotype=state['_evotype']) -# self.__dict__.update(g.__dict__) -# -# def ModelMember_setstate(self, state): -# if "dirty" in state: # .dirty was replaced with ._dirty -# state['_dirty'] = state['dirty'] -# del state['dirty'] -# self.__dict__.update(state) -# -# #Modules -# gatestring = _ModuleType("gatestring") -# gatestring.GateString = dummy_GateString -# gatestring.CompressedGateString = dummy_CompressedGateString -# _sys.modules['pygsti.objects.gatestring'] = gatestring -# #_objs.circuit.Circuit.__setstate__ = GateString_setstate Never needed now -# -# gateset = _ModuleType("gateset") -# gateset.GateSet = dummy_GateSet -# _sys.modules['pygsti.objects.gateset'] = gateset -# -# gate = _ModuleType("gate") -# gate.EigenvalueParameterizedGate = _objs.EigenvalueParamDenseOp -# gate.LinearlyParameterizedGate = _objs.LinearlyParamDenseOp -# #gate.LindbladParameterizedGateMap = _objs.LindbladOp # no upgrade code for this yet -# gate.LindbladParameterizedGate = dummy_LindbladParameterizedGate -# _objs.LindbladDenseOp.__setstate__ = Lind_setstate # dummy_LindbladParameterizedGate.__setstate__ -# gate.FullyParameterizedGate = _objs.FullDenseOp -# gate.TPParameterizedGate = _objs.TPDenseOp -# gate.GateMatrix = _objs.DenseOperator -# gate.ComposedGateMap = _objs.ComposedOp -# gate.EmbeddedGateMap = _objs.EmbeddedOp -# gate.ComposedGate = _objs.ComposedDenseOp -# gate.EmbeddedGate = _objs.EmbeddedDenseOp -# gate.StaticGate = _objs.StaticDenseOp -# gate.LinearlyParameterizedElementTerm = _objs.operation.LinearlyParameterizedElementTerm -# #MapOp = _objs.MapOperator -# _sys.modules['pygsti.objects.gate'] = gate -# -# # spamvec = _ModuleType("spamvec") #already exists - just add to it -# spamvec = _sys.modules['pygsti.objects.spamvec'] -# spamvec.LindbladParameterizedSPAMVec = _objs.LindbladSPAMVec -# spamvec.FullyParameterizedSPAMVec = _objs.FullSPAMVec -# spamvec.CPTPParameterizedSPAMVec = _objs.CPTPSPAMVec -# spamvec.TPParameterizedSPAMVec = _objs.TPSPAMVec -# -# povm = _sys.modules['pygsti.objects.povm'] -# povm.LindbladParameterizedPOVM = _objs.LindbladPOVM -# -# #Don't need class logic here b/c we just store the class itself in a model object: -# gatematrixcalc = _ModuleType("gatematrixcalc") -# gatematrixcalc.GateMatrixCalc = _objs.matrixforwardsim.MatrixForwardSimulator # dummy_GateMatrixCalc -# _sys.modules['pygsti.objects.gatematrixcalc'] = gatematrixcalc -# -# autogator = _ModuleType("autogator") -# autogator.AutoGator = dummy_AutoGator -# autogator.SimpleCompositionAutoGator = dummy_SimpleCompositionAutoGator -# _sys.modules['pygsti.objects.autogator'] = autogator -# -# #These have been removed now! -# #gatestringstructure = _ModuleType("gatestringstructure") -# #gatestringstructure.GatestringPlaquette = _objs.circuitstructure.CircuitPlaquette -# #gatestringstructure.GateStringStructure = _objs.CircuitStructure -# #gatestringstructure.LsGermsStructure = _objs.LsGermsStructure -# -# #_sys.modules['pygsti.objects.gatestringstructure'] = gatestringstructure -# -# _objs.modelmember.ModelMember.__setstate__ = ModelMember_setstate -# -# if old_version <= totup("0.9.7.1"): -# class dummy_Basis(object): -# def __new__(cls): -# replacement_obj = _objs.basis.BuiltinBasis.__new__(_objs.basis.BuiltinBasis) -# return replacement_obj -# -# def __setstate__(self, state): -# return Basis_setstate(self, state) -# -# def Basis_setstate(self, state): -# if "labels" in state: # .label was replaced with ._label -# state['_labels'] = state['labels'] -# del state['labels'] -# -# if "name" in state and state['name'] in ('pp', 'std', 'gm', 'qt', 'unknown') and 'dim' in state: -# dim = state['dim'].opDim if hasattr(state['dim'], 'opDim') else state['dim'] -# assert(isinstance(dim, _numbers.Integral)) -# sparse = state['sparse'] if ('sparse' in state) else False -# newBasis = _objs.BuiltinBasis(state['name'], int(dim), sparse) -# self.__class__ = _objs.basis.BuiltinBasis -# self.__dict__.update(newBasis.__dict__) -# else: -# raise ValueError("Can only load old *builtin* basis objects!") -# -# class dummy_Dim(object): -# def __setstate__(self, state): # was Dim_setstate -# if "gateDim" in state: # .label was replaced with ._label -# state['opDim'] = state['gateDim'] -# del state['gateDim'] -# self.__dict__.update(state) -# -# def StateSpaceLabels_setstate(self, state): -# squared_labeldims = {k: int(d**2) for k, d in state['labeldims'].items()} -# squared_dims = [tuple((squared_labeldims[lbl] for lbl in tpbLbls)) -# for tpbLbls in state['labels']] -# sslbls = _objs.StateSpaceLabels(state['labels'], squared_dims) -# self.__dict__.update(sslbls.__dict__) -# -# #DEBUG!!! -# #print("!!setstate:") -# #print(state) -# #assert(False),"STOP" -# -# def Circuit_setstate(self, state): -# if old_version == totup("0.9.6"): # b/c this clobbers older-version upgrade -# state = GateString_setstate(self, state) -# -# if 'line_labels' in state: line_labels = state['line_labels'] -# elif '_line_labels' in state: line_labels = state['_line_labels'] -# else: raise ValueError("Cannot determing line labels from old Circuit state: %s" % str(state.keys())) -# -# if state['_str']: # then rely on string rep to init new circuit -# c = _objs.Circuit(None, line_labels, editable=not state['_static'], stringrep=state['_str']) -# else: -# -# if 'labels' in state: labels = state['labels'] -# elif '_labels' in state: labels = state['_labels'] -# else: raise ValueError("Cannot determing labels from old Circuit state: %s" % str(state.keys())) -# c = _objs.Circuit(labels, line_labels, editable=not state['_static']) -# -# self.__dict__.update(c.__dict__) -# -# def Hack_CompressedCircuit_expand(self): -# """ Hacked version to rely on string rep & re-parse if it's there """ -# return _objs.Circuit(None, self._line_labels, editable=False, stringrep=self._str) -# -# def SPAMVec_setstate(self, state): -# if "dirty" in state: # backward compat: .dirty was replaced with ._dirty in ModelMember -# state['_dirty'] = state['dirty']; del state['dirty'] -# self.__dict__.update(state) -# -# dim = _ModuleType("dim") -# dim.Dim = dummy_Dim -# _sys.modules['pygsti.baseobjs.dim'] = dim -# -# #_objs.basis.saved_Basis = _objs.basis.Basis -# #_objs.basis.Basis = dummy_Basis -# _objs.basis.Basis.__setstate__ = Basis_setstate -# _circuits.circuit.Circuit.__setstate__ = Circuit_setstate -# _objs.labeldicts.StateSpaceLabels.__setstate__ = StateSpaceLabels_setstate -# _circuits.circuit.CompressedCircuit.saved_expand = pygsti.circuits.circuit.CompressedCircuit.expand -# _circuits.circuit.CompressedCircuit.expand = Hack_CompressedCircuit_expand -# _objs.spamvec.SPAMVec.__setstate__ = SPAMVec_setstate -# -# if old_version < totup("0.9.9"): -# -# def SPAMVec_setstate(self, state): -# #Note: include "dirty" -# if old_version <= totup("0.9.7.1"): # b/c this clobbers older-version upgrade -# if "dirty" in state: # backward compat: .dirty was replaced with ._dirty in ModelMember -# state['_dirty'] = state['dirty']; del state['dirty'] -# if "_prep_or_effect" not in state: -# state['_prep_or_effect'] = "unknown" -# if "base1D" not in state and 'base' in state: -# state['base1D'] = state['base'].flatten() -# del state['base'] -# -# self.__dict__.update(state) -# -# #HERE TODO: need to remake/add ._reps to all spam & operation objects -# -# _objs.spamvec.SPAMVec.__setstate__ = SPAMVec_setstate -# -# # Compatibility with refactored `baseobjs` API -# _sys.modules['pygsti.baseobjs.smartcache'] = _objs.smartcache -# _sys.modules['pygsti.baseobjs.verbosityprinter'] = _objs.verbosityprinter -# _sys.modules['pygsti.baseobjs.profiler'] = pygsti.baseobjs.profiler -# _sys.modules['pygsti.baseobjs.protectedarray'] = _objs.protectedarray -# _sys.modules['pygsti.baseobjs.objectivefns'] = pygsti.objectivefns.objectivefns -# _sys.modules['pygsti.baseobjs.basis'] = _objs.basis -# _sys.modules['pygsti.baseobjs.label'] = _objs.label -# -# if old_version < totup("0.9.9.1"): -# -# def DenseOperator_setstate(self, state): -# if "base" in state: -# del state['base'] -# self.__dict__.update(state) -# -# def DenseSPAMVec_setstate(self, state): -# if old_version <= totup("0.9.9"): # b/c this clobbers (or shadows) older-version upgrade -# if old_version <= totup("0.9.7.1"): # b/c this clobbers older-version upgrade -# if "dirty" in state: # backward compat: .dirty was replaced with ._dirty in ModelMember -# state['_dirty'] = state['dirty']; del state['dirty'] -# if "_prep_or_effect" not in state: -# state['_prep_or_effect'] = "unknown" -# if "base1D" not in state and 'base' in state: -# state['base1D'] = state['base'].flatten() -# del state['base'] -# -# if "base" in state: -# del state['base'] -# if "base1D" in state: -# del state['base1D'] -# self.__dict__.update(state) -# -# _objs.spamvec.DenseSPAMVec.__setstate__ = DenseSPAMVec_setstate -# _objs.operation.DenseOperator.__setstate__ = DenseOperator_setstate -# -# yield # body of context-manager block -# -# if old_version <= totup("0.9.6"): -# del _sys.modules['pygsti.objects.gatestring'] -# del _sys.modules['pygsti.objects.gateset'] -# del _sys.modules['pygsti.objects.gate'] -# del _sys.modules['pygsti.objects.gatematrixcalc'] -# del _sys.modules['pygsti.objects.autogator'] -# #del _sys.modules['pygsti.objects.gatestringstructure'] -# -# del _sys.modules['pygsti.objects.spamvec'].LindbladParameterizedSPAMVec -# del _sys.modules['pygsti.objects.spamvec'].FullyParameterizedSPAMVec -# del _sys.modules['pygsti.objects.spamvec'].CPTPParameterizedSPAMVec -# del _sys.modules['pygsti.objects.spamvec'].TPParameterizedSPAMVec -# -# del _sys.modules['pygsti.objects.povm'].LindbladParameterizedPOVM -# -# delattr(_objs.Circuit, '__setstate__') -# delattr(_objs.LindbladDenseOp, '__setstate__') -# delattr(_objs.modelmember.ModelMember, '__setstate__') -# -# if old_version <= totup("0.9.7.1"): -# del _sys.modules['pygsti.baseobjs.dim'] -# delattr(_objs.Basis, '__setstate__') -# delattr(_objs.labeldicts.StateSpaceLabels, '__setstate__') -# if hasattr(_objs.Circuit, '__setstate__'): # b/c above block may have already deleted this -# delattr(_objs.Circuit, '__setstate__') -# pygsti.circuits.circuit.CompressedCircuit.expand = pygsti.circuits.circuit.CompressedCircuit.saved_expand -# delattr(pygsti.circuits.circuit.CompressedCircuit, 'saved_expand') -# delattr(_objs.spamvec.SPAMVec, '__setstate__') -# -# if old_version < totup("0.9.9"): -# if hasattr(_objs.spamvec.SPAMVec, '__setstate__'): # b/c above block may have already deleted this -# delattr(_objs.spamvec.SPAMVec, '__setstate__') -# -# del _sys.modules['pygsti.baseobjs.smartcache'] -# del _sys.modules['pygsti.baseobjs.verbosityprinter'] -# del _sys.modules['pygsti.baseobjs.profiler'] -# del _sys.modules['pygsti.baseobjs.protectedarray'] -# del _sys.modules['pygsti.baseobjs.objectivefns'] -# del _sys.modules['pygsti.baseobjs.basis'] -# del _sys.modules['pygsti.baseobjs.label'] -# -# if old_version < totup("0.9.9.1"): -# delattr(_objs.spamvec.DenseSPAMVec, '__setstate__') -# delattr(_objs.operation.DenseOperator, '__setstate__') diff --git a/pygsti/modelmembers/operations/affineshiftop.py b/pygsti/modelmembers/operations/affineshiftop.py index 9aaacb120..daf48f84e 100644 --- a/pygsti/modelmembers/operations/affineshiftop.py +++ b/pygsti/modelmembers/operations/affineshiftop.py @@ -126,6 +126,7 @@ def to_vector(self): numpy array The operation parameters as a 1D array with length num_params(). """ + # Use flatten (rather than ravel) to ensure a copy is made. return self._ptr[1:,0].flatten() # .real in case of complex matrices? def from_vector(self, v, close=False, dirty_value=True): diff --git a/pygsti/modelmembers/operations/eigpdenseop.py b/pygsti/modelmembers/operations/eigpdenseop.py index 8c1e6ae59..6173681fe 100644 --- a/pygsti/modelmembers/operations/eigpdenseop.py +++ b/pygsti/modelmembers/operations/eigpdenseop.py @@ -432,13 +432,13 @@ def deriv_wrt_params(self, wrt_filter=None): dMx = _np.zeros((self.dim, self.dim), 'complex') for prefactor, (i, j) in pdesc: dMx[i, j] = prefactor - tmp = _np.dot(self.B, _np.dot(dMx, self.Bi)) + tmp = self.B @ (dMx, self.Bi) if _np.linalg.norm(tmp.imag) >= IMAG_TOL: # just a warning until we figure this out. print("EigenvalueParamDenseOp deriv_wrt_params WARNING:" " Imag part = ", _np.linalg.norm(tmp.imag), " pdesc = ", pdesc) # pragma: no cover #assert(_np.linalg.norm(tmp.imag) < IMAG_TOL), \ # "Imaginary mag = %g!" % _np.linalg.norm(tmp.imag) - derivMx[:, k] = tmp.real.flatten() + derivMx[:, k] = tmp.real.ravel() if wrt_filter is None: return derivMx diff --git a/pygsti/modelmembers/operations/fullarbitraryop.py b/pygsti/modelmembers/operations/fullarbitraryop.py index b941cca9c..62a7409a0 100644 --- a/pygsti/modelmembers/operations/fullarbitraryop.py +++ b/pygsti/modelmembers/operations/fullarbitraryop.py @@ -93,6 +93,7 @@ def to_vector(self): numpy array The operation parameters as a 1D array with length num_params(). """ + # Use flatten (rather than ravel) to ensure a copy is made. return self._ptr.flatten() def from_vector(self, v, close=False, dirty_value=True): diff --git a/pygsti/modelmembers/operations/fulltpop.py b/pygsti/modelmembers/operations/fulltpop.py index faee6963d..761894229 100644 --- a/pygsti/modelmembers/operations/fulltpop.py +++ b/pygsti/modelmembers/operations/fulltpop.py @@ -122,7 +122,7 @@ def to_vector(self): numpy array The operation parameters as a 1D array with length num_params(). """ - return self._ptr.flatten()[self.dim:] # .real in case of complex matrices? + return self._ptr.ravel()[self.dim:].copy() # .real in case of complex matrices? def from_vector(self, v, close=False, dirty_value=True): """ diff --git a/pygsti/modelmembers/operations/fullunitaryop.py b/pygsti/modelmembers/operations/fullunitaryop.py index 728a301bb..c75bec72b 100644 --- a/pygsti/modelmembers/operations/fullunitaryop.py +++ b/pygsti/modelmembers/operations/fullunitaryop.py @@ -98,7 +98,8 @@ def to_vector(self): numpy array The operation parameters as a 1D array with length num_params(). """ - return _np.concatenate((self._ptr.real.flatten(), self._ptr.imag.flatten()), axis=0) + # _np.concatenate will make a copy for us, so use ravel instead of flatten. + return _np.concatenate((self._ptr.real.ravel(), self._ptr.imag.ravel()), axis=0) def from_vector(self, v, close=False, dirty_value=True): """ diff --git a/pygsti/modelmembers/povms/__init__.py b/pygsti/modelmembers/povms/__init__.py index e946abd51..3fc28cc29 100644 --- a/pygsti/modelmembers/povms/__init__.py +++ b/pygsti/modelmembers/povms/__init__.py @@ -125,8 +125,8 @@ def create_from_dmvecs(superket_vectors, povm_type, basis='pp', evotype='default EffectiveExpErrorgen = _IdentityPlusErrorgenOp if lndtype.meta == '1+' else _ExpErrorgenOp povm = ComposedPOVM(EffectiveExpErrorgen(errorgen), base_povm, mx_basis=basis) elif typ in ('computational', 'static pure', 'full pure'): - # RESHAPE NOTE: .flatten() added to line below (to convert pure *col* vec -> 1D) to fix unit tests - pure_vectors = {k: _ot.dmvec_to_state(_bt.change_basis(superket, basis, 'std')).flatten() + # RESHAPE NOTE: .ravel() added to line below (to convert pure *col* vec -> 1D) to fix unit tests + pure_vectors = {k: _ot.dmvec_to_state(_bt.change_basis(superket, basis, 'std')).ravel() for k, superket in superket_vectors.items()} povm = create_from_pure_vectors(pure_vectors, typ, basis, evotype, state_space) else: @@ -164,7 +164,7 @@ def create_effect_from_pure_vector(pure_vector, effect_type, basis='pp', evotype superket = _bt.change_basis(_ot.state_to_dmvec(pure_vector), 'std', basis) ef = create_effect_from_dmvec(superket, typ, basis, evotype, state_space) elif typ == 'static clifford': - ef = ComputationalBasisPOVMEffect.from_pure_vector(pure_vector.flatten()) + ef = ComputationalBasisPOVMEffect.from_pure_vector(pure_vector.ravel()) elif _ot.is_valid_lindblad_paramtype(typ): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp from ..operations import IdentityPlusErrorgenOp as _IdentityPlusErrorgenOp diff --git a/pygsti/modelmembers/states/computationalstate.py b/pygsti/modelmembers/states/computationalstate.py index 9e57cd956..1d4114856 100644 --- a/pygsti/modelmembers/states/computationalstate.py +++ b/pygsti/modelmembers/states/computationalstate.py @@ -88,7 +88,7 @@ def from_state_vector(cls, vec, basis='pp', evotype='default', state_space=None) for zvals in _itertools.product(*([(0, 1)] * nqubits)): testvec = _functools.reduce(_np.kron, [v[i] for i in zvals]) - if _np.allclose(testvec, vec.flatten()): + if _np.allclose(testvec, vec.ravel()): return cls(zvals, basis, evotype, state_space) raise ValueError(("Given `vec` is not a z-basis product state - " "cannot construct ComputationalBasisState")) @@ -128,7 +128,7 @@ def from_pure_vector(cls, purevec, basis='pp', evotype="default", state_space=No v = (_np.array([1, 0], 'd'), _np.array([0, 1], 'd')) # (v0,v1) for zvals in _itertools.product(*([(0, 1)] * nqubits)): testvec = _functools.reduce(_np.kron, [v[i] for i in zvals]) - if _np.allclose(testvec, purevec.flatten()): + if _np.allclose(testvec, purevec.ravel()): return cls(zvals, basis, evotype, state_space) raise ValueError(("Given `purevec` must be a z-basis product state - " "cannot construct ComputationalBasisState")) diff --git a/pygsti/modelmembers/states/state.py b/pygsti/modelmembers/states/state.py index b3ed55cf9..dd7d8225b 100644 --- a/pygsti/modelmembers/states/state.py +++ b/pygsti/modelmembers/states/state.py @@ -573,4 +573,4 @@ def _to_vector(v): vector = _np.array(v, typ)[:, None] # make into a 2-D column vec assert(len(vector.shape) == 2 and vector.shape[1] == 1) - return vector.flatten() # HACK for convention change -> (N,) instead of (N,1) + return vector.ravel() # HACK for convention change -> (N,) instead of (N,1) diff --git a/pygsti/models/explicitcalc.py b/pygsti/models/explicitcalc.py index 70d1e20a4..8cd54681b 100644 --- a/pygsti/models/explicitcalc.py +++ b/pygsti/models/explicitcalc.py @@ -283,7 +283,7 @@ def residuals(self, other_calc, transform_mx=None, item_weights=None): wt * Evec.residuals(other_calc.effects[lbl])) nSummands += wt**2 * Evec.dim - resids = [r.flatten() for r in resids] + resids = [r.ravel() for r in resids] resids = _np.concatenate(resids) return resids, nSummands @@ -545,7 +545,7 @@ def _buildup_dpg(self): # parameterization object, which gives a vector of length # equal to the number of model *elements*. to_vector = _np.concatenate( - [obj.flatten() for obj in _itertools.chain( + [obj.ravel() for obj in _itertools.chain( mdlDeriv_preps.values(), mdlDeriv_effects.values(), mdlDeriv_ops.values())], axis=0) dPG[:, nParams + i * dim + j] = to_vector @@ -688,7 +688,7 @@ def _gauge_orbit_curvature(self, item_weights=None, non_gauge_mix_mx=None): - unitMx_i @ gate @ unitMx_j - unitMx_j @ gate @ unitMx_i to_vector = _np.concatenate( - [obj.flatten() for obj in _itertools.chain( + [obj.ravel() for obj in _itertools.chain( mdlHess_preps.values(), mdlHess_effects.values(), mdlHess_ops.values())], axis=0) Heps[:, i1 * dim + i2, j1 * dim + j2] = to_vector diff --git a/pygsti/models/modelconstruction.py b/pygsti/models/modelconstruction.py index b986f2c4e..7b38b34a7 100644 --- a/pygsti/models/modelconstruction.py +++ b/pygsti/models/modelconstruction.py @@ -99,7 +99,7 @@ def create_spam_vector(vec_expr, state_space, basis): std_basis = basis.create_equivalent('std') vecInSimpleStdBasis = _np.zeros(std_basis.elshape, 'd') # a matrix, but flattened it is our spamvec vecInSimpleStdBasis[index, index] = 1.0 # now a matrix with just a single 1 on the diag - vecInReducedStdBasis = _np.dot(std_basis.from_elementstd_transform_matrix, vecInSimpleStdBasis.flatten()) + vecInReducedStdBasis = std_basis.from_elementstd_transform_matrix @ vecInSimpleStdBasis.ravel() # translates the density matrix / state vector to the std basis with our desired block structure vec = _bt.change_basis(vecInReducedStdBasis, std_basis, basis) diff --git a/pygsti/protocols/confidenceregionfactory.py b/pygsti/protocols/confidenceregionfactory.py index 4369f289e..8346b86fc 100644 --- a/pygsti/protocols/confidenceregionfactory.py +++ b/pygsti/protocols/confidenceregionfactory.py @@ -691,13 +691,13 @@ def _objective_func(vector_m): sub_crf.project_hessian('none') crfv = sub_crf.view(level) - operationCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(gl).flatten() + operationCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(gl).ravel() for gl in model.operations]) return _np.sqrt(_np.sum(operationCIs**2)) #Run Minimization Algorithm startM = _np.zeros((self.nNonGaugeParams, self.nGaugeParams), 'd') - x0 = startM.flatten() + x0 = startM.ravel() print_obj_func = _opt.create_objfn_printer(_objective_func) minSol = _opt.minimize(_objective_func, x0, method=method, maxiter=maxiter, @@ -727,7 +727,7 @@ def _opt_projection_from_split(self, verbosity=0): self.circuit_list_lbl, projected_hessian, 0.0) sub_crf.project_hessian('none') crfv = sub_crf.view(level) - operationCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(gl).flatten() + operationCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(gl).ravel() for gl in model.operations]) op_intrinsic_err = _np.sqrt(_np.mean(operationCIs**2)) @@ -738,7 +738,7 @@ def _opt_projection_from_split(self, verbosity=0): self.circuit_list_lbl, projected_hessian, 0.0) sub_crf.project_hessian('none') crfv = sub_crf.view(level) - spamCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(sl).flatten() + spamCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(sl).ravel() for sl in _itertools.chain(iter(model.preps), iter(model.povms))]) spam_intrinsic_err = _np.sqrt(_np.mean(spamCIs**2)) @@ -755,9 +755,9 @@ def _opt_projection_from_split(self, verbosity=0): sub_crf.project_hessian('none') crfv = sub_crf.view(level) - operationCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(gl).flatten() + operationCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(gl).ravel() for gl in model.operations]) - spamCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(sl).flatten() + spamCIs = _np.concatenate([crfv.retrieve_profile_likelihood_confidence_intervals(sl).ravel() for sl in _itertools.chain(iter(model.preps), iter(model.povms))]) op_err = _np.sqrt(_np.mean(operationCIs**2)) diff --git a/pygsti/report/mpl_colormaps.py b/pygsti/report/mpl_colormaps.py index 7ae57269f..22d1e8b47 100644 --- a/pygsti/report/mpl_colormaps.py +++ b/pygsti/report/mpl_colormaps.py @@ -540,7 +540,7 @@ def _get_minor_tics(t): axes.bar(x, y, barWidth, color=color) else: axes.bar(x, y, barWidth, color=color, - yerr=yerr.flatten().real) + yerr=yerr.ravel().real) if xtickvals is not None: xtics = _np.array(xtickvals) + 0.5 # _np.arange(plt_data.shape[1])+0.5 diff --git a/pygsti/report/plothelpers.py b/pygsti/report/plothelpers.py index eeba19eec..8aac73312 100644 --- a/pygsti/report/plothelpers.py +++ b/pygsti/report/plothelpers.py @@ -103,7 +103,7 @@ def _eformat(f, prec): def _num_non_nan(array): - ixs = _np.where(_np.isnan(_np.array(array).flatten()) == False)[0] # noqa: E712 + ixs = _np.where(_np.isnan(_np.array(array).ravel()) == False)[0] # noqa: E712 return int(len(ixs)) @@ -147,7 +147,7 @@ def _compute_num_boxes_dof(sub_mxs, sum_up, element_dof): # Gets all the non-NaN boxes, flattens the resulting # array, and does the sum. - n_boxes = _np.sum(~_np.isnan(sub_mxs).flatten()) + n_boxes = _np.sum(~_np.isnan(sub_mxs).ravel()) return n_boxes, dof_per_box diff --git a/pygsti/report/reportables.py b/pygsti/report/reportables.py index 0d37389bb..67cf9bdf1 100644 --- a/pygsti/report/reportables.py +++ b/pygsti/report/reportables.py @@ -1778,7 +1778,6 @@ def errorgen_and_projections(errgen, mx_basis): 'stochastic', and 'affine'. """ ret = {} - #egnorm = _np.linalg.norm(errgen.flatten()) ret['error generator'] = errgen if set(mx_basis.name.split('*')) == set(['pp']): @@ -2021,7 +2020,7 @@ def error_generator_jacobian(opstr): for i, gl in enumerate(opLabels): for k, errOnGate in enumerate(error_superops): noise = first_order_noise(opstr, errOnGate, gl) - jac[:, i * nSuperOps + k] = [_np.vdot(errOut.flatten(), noise.flatten()) for errOut in error_superops] + jac[:, i * nSuperOps + k] = [_np.vdot(errOut.ravel(), noise.ravel()) for errOut in error_superops] # DEBUG CHECK check = [] @@ -2162,9 +2161,8 @@ def general_decomposition(model_a, model_b): decomp[str(gl) + "," + str(gl_other) + " axis angle"] = 10000.0 # sentinel for irrelevant angle real_dot = _np.clip( - _np.real(_np.dot(decomp[str(gl) + ' axis'].flatten(), - decomp[str(gl_other) + ' axis'].flatten())), - -1.0, 1.0) + _np.real(_np.vdot(decomp[str(gl) + ' axis'], decomp[str(gl_other) + ' axis'])), + -1.0, 1.0) angle = _np.arccos(real_dot) / _np.pi decomp[str(gl) + "," + str(gl_other) + " axis angle"] = angle diff --git a/pygsti/report/workspaceplots.py b/pygsti/report/workspaceplots.py index 5dd53332b..1e6a105f7 100644 --- a/pygsti/report/workspaceplots.py +++ b/pygsti/report/workspaceplots.py @@ -380,9 +380,9 @@ def val_filter(vals): def sum_up_mx(mx): """ Sum up `mx` in a NAN-ignoring way """ - flat_mx = mx.flatten() - if any([_np.isnan(x) for x in flat_mx]): - if all([_np.isnan(x) for x in flat_mx]): + flat_mx = mx.ravel() + if _np.any(_np.isnan(flat_mx)): + if _np.all(_np.isnan(flat_mx)): return _np.nan # replace NaNs with zeros for purpose of summing (when there's at least one non-NaN) return sum(_np.nan_to_num(flat_mx)) @@ -2567,7 +2567,7 @@ def _create(self, evals_list, colors, labels, scale, amp, center_text): color = colors[i] if (colors is not None) else "black" trace = go.Scatterpolar( r=list(_np.absolute(evals).flat), - theta=list(_np.angle(evals).flatten() * (180.0 / _np.pi)), + theta=list(_np.angle(evals).ravel() * (180.0 / _np.pi)), mode='markers', marker=dict( color=color,