def create_from_pure_vector(pure_vector, state_type, basis='pp', evotype='default', state_space=None, on_construction_error='warn'): """ TODO: docstring -- create a State from a state vector """ state_type_preferences = (state_type, ) if isinstance(state_type, str) else state_type if state_space is None: state_space = _statespace.default_space_for_udim(len(pure_vector)) for typ in state_type_preferences: try: if typ == 'computational': st = ComputationalBasisState.from_pure_vector( pure_vector, basis, evotype, state_space) #elif typ == ('static stabilizer', 'static clifford'): # st = StaticStabilizerState(...) # TODO elif typ == 'static pure': st = StaticPureState(pure_vector, basis, evotype, state_space) elif typ == 'full pure': st = FullPureState(pure_vector, basis, evotype, state_space) elif typ in ('static', 'full', 'full TP', 'TrueCPTP'): superket = _bt.change_basis(_ot.state_to_dmvec(pure_vector), 'std', basis) st = create_from_dmvec(superket, typ, basis, evotype, state_space) elif _ot.is_valid_lindblad_paramtype(typ): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp static_state = create_from_pure_vector( pure_vector, ('computational', 'static pure'), basis, evotype, state_space) proj_basis = 'PP' if state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator( state_space.dim, typ, proj_basis, basis, truncate=True, evotype=evotype, state_space=state_space) st = ComposedState(static_state, _ExpErrorgenOp(errorgen)) else: raise ValueError("Unknown state type '%s'!" % str(typ)) return st # if we get to here, then we've successfully created a state to return except (ValueError, AssertionError) as err: if on_construction_error == 'raise': raise err elif on_construction_error == 'warn': print( 'Failed to construct state with type "{}" with error: {}'. format(typ, str(err))) pass # move on to next type raise ValueError( "Could not create a state of type(s) %s from the given pure vector!" % (str(state_type)))
def create_from_dmvec(superket_vector, state_type, basis='pp', evotype='default', state_space=None): state_type_preferences = (state_type, ) if isinstance(state_type, str) else state_type if state_space is None: state_space = _statespace.default_space_for_dim(len(superket_vector)) for typ in state_type_preferences: try: if typ == "static": st = StaticState(superket_vector, evotype, state_space) elif typ == "full": st = FullState(superket_vector, evotype, state_space) elif typ == "full TP": st = TPState(superket_vector, basis, evotype, state_space) elif typ == "TrueCPTP": # a non-lindbladian CPTP state that hasn't worked well... truncate = False st = CPTPState(superket_vector, basis, truncate, evotype, state_space) elif _ot.is_valid_lindblad_paramtype(typ): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp try: dmvec = _bt.change_basis(superket_vector, basis, 'std') purevec = _ot.dmvec_to_state( dmvec ) # raises error if dmvec does not correspond to a pure state static_state = StaticPureState(purevec, basis, evotype, state_space) except ValueError: static_state = StaticState(superket_vector, evotype, state_space) proj_basis = 'PP' if state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator( state_space.dim, typ, proj_basis, basis, truncate=True, evotype=evotype) return ComposedState(static_state, _ExpErrorgenOp(errorgen)) else: # Anything else we try to convert to a pure vector and convert the pure state vector dmvec = _bt.change_basis(superket_vector, basis, 'std') purevec = _ot.dmvec_to_state(dmvec) st = create_from_pure_vector(purevec, typ, basis, evotype, state_space) return st except (ValueError, AssertionError): pass # move on to next type raise ValueError( "Could not create a state of type(s) %s from the given superket vector!" % (str(state_type)))
def create_from_unitary_mx(unitary_mx, op_type, basis='pp', stdname=None, evotype='default', state_space=None): """ TODO: docstring - note that op_type can be a list/tuple of types in order of precedence """ op_type_preferences = verbose_type_from_op_type(op_type) error_msgs = {} U = unitary_mx if state_space is None: state_space = _statespace.default_space_for_udim(U.shape[0]) for typ in op_type_preferences: try: if typ == 'static standard' and stdname is not None: op = StaticStandardOp(stdname, basis, evotype, state_space) elif typ == 'static clifford': op = StaticCliffordOp(U, None, basis, evotype, state_space) elif typ == 'static unitary': op = StaticUnitaryOp(U, basis, evotype, state_space) elif typ == "full unitary": op = FullUnitaryOp(U, basis, evotype, state_space) elif typ in ('static', 'full', 'full TP', 'linear'): superop_mx = _ot.unitary_to_superop(U, basis) op = create_from_superop_mx(superop_mx, op_type, basis, stdname, evotype, state_space) elif _ot.is_valid_lindblad_paramtype(typ): # maybe "lindblad XXX" where XXX is a valid lindblad type? if _np.allclose(U, _np.identity(U.shape[0], 'd')): unitary_postfactor = None else: unitary_postfactor = create_from_unitary_mx( U, ('static standard', 'static clifford', 'static unitary'), basis, stdname, evotype, state_space) proj_basis = 'PP' if state_space.is_entirely_qubits else basis errorgen = LindbladErrorgen.from_error_generator(state_space.dim, typ, proj_basis, basis, truncate=True, evotype=evotype, state_space=state_space) op = ExpErrorgenOp(errorgen) if (unitary_postfactor is None) \ else ComposedOp([unitary_postfactor, ExpErrorgenOp(errorgen)]) if op.dim <= 16: # only do this for up to 2Q operations, otherwise to_dense is too expensive expected_superop_mx = _ot.unitary_to_superop(U, basis) assert (_np.linalg.norm(op.to_dense('HilbertSchmidt') - expected_superop_mx) < 1e-6), \ "Failure to create Lindblad operation (maybe due the complex log's branch cut?)" else: raise ValueError("Unknown operation type '%s'!" % str(typ)) return op # if we get to here, then we've successfully created an op to return except (ValueError, AssertionError, AttributeError) as e: #_warnings.warn('Failed to create operator with type %s with error: %s' % (typ, e)) error_msgs[typ] = str(e) # # move on to text type raise ValueError("Could not create an operator of type(s) %s from the given unitary op:\n%s" % (str(op_type), str(error_msgs)))
def povm_type_from_op_type(op_type): """Decode an op type into an appropriate povm type. Parameters: ----------- op_type: str or list of str Operation parameterization type (or list of preferences) Returns ------- povm_type_preferences: tuple of str POVM parameterization types """ op_type_preferences = _mm.operations.verbose_type_from_op_type(op_type) # computational and TP are directly constructed as POVMS # All others pass through to the effects povm_conversion = { 'auto': 'computational', 'static standard': 'computational', 'static clifford': 'computational', 'static unitary': 'static pure', 'full unitary': 'full pure', 'static': 'static', 'full': 'full', 'full TP': 'full TP', 'linear': 'full', } povm_type_preferences = [] for typ in op_type_preferences: povm_type = None if _ot.is_valid_lindblad_paramtype(typ): # Lindblad types are passed through povm_type = typ else: povm_type = povm_conversion.get(typ, None) if povm_type is None: continue if povm_type not in povm_type_preferences: povm_type_preferences.append(povm_type) if len(povm_type_preferences) == 0: raise ValueError( 'Could not convert any op types from {}.\n'.format(op_type_preferences) + '\tKnown op_types: Lindblad types or {}\n'.format(sorted(list(povm_conversion.keys()))) + '\tValid povm_types: Lindblad types or {}'.format(sorted(list(set(povm_conversion.values())))) ) return povm_type_preferences
def state_type_from_op_type(op_type): """Decode an op type into an appropriate state type. Parameters: ----------- op_type: str or list of str Operation parameterization type (or list of preferences) Returns ------- str State parameterization type """ op_type_preferences = _mm.operations.verbose_type_from_op_type(op_type) state_conversion = { 'auto': 'computational', 'static standard': 'computational', 'static clifford': 'computational', 'static unitary': 'static pure', 'full unitary': 'full pure', 'static': 'static', 'full': 'full', 'full TP': 'full TP', 'linear': 'full', } state_type_preferences = [] for typ in op_type_preferences: state_type = None if _ot.is_valid_lindblad_paramtype(typ): # Lindblad types are passed through state_type = typ else: state_type = state_conversion.get(typ, None) if state_type is None: continue if state_type not in state_type_preferences: state_type_preferences.append(state_type) if len(state_type_preferences) == 0: raise ValueError('Could not convert any op types from {}.\n'.format( op_type_preferences) + '\tKnown op_types: Lindblad types or {}\n'.format( sorted(list(state_conversion.keys()))) + '\tValid state_types: Lindblad types or {}'.format( sorted(list(set(state_conversion.values()))))) return state_type_preferences
def verbose_type_from_op_type(op_type): """Decode an op type into the "canonical", more verbose op type. Parameters: ----------- op_type: str or list of str Operation parameterization type (or list of preferences) Returns ------- povm_type_preferences: tuple of str POVM parameterization types """ op_type_preferences = (op_type,) if isinstance(op_type, str) else op_type verbose_conversion = { 'static standard': 'static standard', 'static clifford': 'static clifford', 'static unitary': 'static unitary', 'full unitary': 'full unitary', 'static': 'static', 'full': 'full', 'full TP': 'full TP', 'TP': 'full TP', 'linear': 'linear', } verbose_type_preferences = [] for typ in op_type_preferences: verbose_type = None if _ot.is_valid_lindblad_paramtype(typ): # TODO: DO we want to prepend with lindblad? verbose_type = typ else: verbose_type = verbose_conversion.get(typ, None) if verbose_type is None: continue if verbose_type not in verbose_type_preferences: verbose_type_preferences.append(verbose_type) if len(verbose_type_preferences) == 0: raise ValueError( 'Could not convert any op types from {}.\n'.format(op_type_preferences) + '\tKnown op_types: Lindblad types or {}\n'.format(sorted(list(verbose_conversion.keys()))) + '\tValid povm_types: Lindblad types or {}'.format(sorted(list(set(verbose_conversion.values())))) ) return tuple(verbose_type_preferences)
def instrument_type_from_op_type(op_type): """Decode an op type into an appropriate instrument type. Parameters: ----------- op_type: str or list of str Operation parameterization type (or list of preferences) Returns ------- instr_type_preferences: tuple of str POVM parameterization types """ op_type_preferences = _mm.operations.verbose_type_from_op_type(op_type) # Limited set (only matching what is in convert) instr_conversion = { 'auto': 'full', 'static unitary': 'static unitary', 'static clifford': 'static clifford', 'static': 'static', 'full': 'full', 'full TP': 'full TP', 'full unitary': 'full unitary', } instr_type_preferences = [] for typ in op_type_preferences: instr_type = None if _ot.is_valid_lindblad_paramtype(typ): # Lindblad types are passed through as TP only (matching current convert logic) instr_type = "full TP" else: instr_type = instr_conversion.get(typ, None) if instr_type is None: continue if instr_type not in instr_type_preferences: instr_type_preferences.append(instr_type) if len(instr_type_preferences) == 0: raise ValueError('Could not convert any op types from {}.\n'.format( op_type_preferences) + '\tKnown op_types: Lindblad types or {}\n'.format( sorted(list(instr_conversion.keys()))) + '\tValid instrument_types: Lindblad types or {}'. format(sorted(list(set(instr_conversion.values()))))) return instr_type_preferences
def create_from_superop_mx(superop_mx, op_type, basis='pp', stdname=None, evotype='default', state_space=None): op_type_preferences = (op_type,) if isinstance(op_type, str) else op_type error_msgs = {} for typ in op_type_preferences: try: if typ == "static": # "static arbitrary"? op = StaticArbitraryOp(superop_mx, evotype, state_space) elif typ == "full": # "full arbitrary"? op = FullArbitraryOp(superop_mx, evotype, state_space) elif typ in ["TP", "full TP"]: op = FullTPOp(superop_mx, evotype, state_space) elif typ == "linear": # "linear arbitrary"? real = _np.isclose(_np.linalg.norm(superop_mx.imag), 0) op = LinearlyParamArbitraryOp(superop_mx, _np.array([]), {}, None, None, real, evotype, state_space) elif _ot.is_valid_lindblad_paramtype(typ): # maybe "lindblad XXX" where XXX is a valid lindblad type? proj_basis = 'PP' if state_space.is_entirely_qubits else basis if _ot.superop_is_unitary(superop_mx, basis): unitary_postfactor = StaticUnitaryOp(_ot.superop_to_unitary(superop_mx, basis, False), basis, evotype, state_space) errorgen = LindbladErrorgen.from_error_generator(state_space.dim, typ, proj_basis, basis, truncate=True, evotype=evotype, state_space=state_space) ret = ComposedOp([unitary_postfactor, ExpErrorgenOp(errorgen)]) else: errorgen = LindbladErrorgen.from_operation_matrix(superop_mx, typ, proj_basis, mx_basis=basis, truncate=True, evotype=evotype, state_space=state_space) ret = ExpErrorgenOp(errorgen) if ret.dim <= 16: # only do this for up to 2Q operations, otherwise to_dense is too expensive assert(_np.linalg.norm(superop_mx - ret.to_dense('HilbertSchmidt')) < 1e-6), "Failure to create CPTP operation (maybe due the complex log's branch cut?)" return ret else: #Anything else we try to convert to a unitary and convert the unitary unitary_mx = _ot.superop_to_unitary(superop_mx, basis) # raises ValueError if superop isn't unitary op = create_from_unitary_mx(unitary_mx, typ, basis, stdname, evotype, state_space) return op # if we get to here, then we've successfully created an op to return except (ValueError, AssertionError) as e: error_msgs[typ] = str(e) # # move on to text type raise ValueError("Could not create an operator of type(s) %s from the given superop:\n%s" % (str(op_type), str(error_msgs)))
def create_from_pure_vectors(pure_vectors, povm_type, basis='pp', evotype='default', state_space=None, on_construction_error='warn'): """ TODO: docstring -- create a POVM from a list/dict of (key, pure-vector) pairs """ povm_type_preferences = (povm_type,) if isinstance(povm_type, str) else povm_type if not isinstance(pure_vectors, dict): # then assume it's a list of (key, value) pairs pure_vectors = _collections.OrderedDict(pure_vectors) if state_space is None: state_space = _statespace.default_space_for_udim(len(next(iter(pure_vectors.values())))) for typ in povm_type_preferences: try: if typ == 'computational': povm = ComputationalBasisPOVM.from_pure_vectors(pure_vectors, evotype, state_space) #elif typ in ('static stabilizer', 'static clifford'): # povm = ComputationalBasisPOVM(...evotype='stabilizer') ?? elif typ in ('static pure', 'full pure', 'static', 'full'): effects = [(lbl, create_effect_from_pure_vector(vec, typ, basis, evotype, state_space)) for lbl, vec in pure_vectors.items()] povm = UnconstrainedPOVM(effects, evotype, state_space) elif typ == 'full TP': effects = [(lbl, create_effect_from_pure_vector(vec, "full", basis, evotype, state_space)) for lbl, vec in pure_vectors.items()] povm = TPPOVM(effects, evotype, state_space) elif _ot.is_valid_lindblad_paramtype(typ): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp base_povm = create_from_pure_vectors(pure_vectors, ('computational', 'static pure'), basis, evotype, state_space) proj_basis = 'PP' if state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator(state_space.dim, typ, proj_basis, basis, truncate=True, evotype=evotype, state_space=state_space) povm = ComposedPOVM(_ExpErrorgenOp(errorgen), base_povm, mx_basis=basis) else: raise ValueError("Unknown POVM type '%s'!" % str(typ)) return povm # if we get to here, then we've successfully created a state to return except (ValueError, AssertionError) as err: if on_construction_error == 'raise': raise err elif on_construction_error == 'warn': print('Failed to construct povm with type "{}" with error: {}'.format(typ, str(err))) pass # move on to next type raise ValueError("Could not create a POVM of type(s) %s from the given pure vectors!" % (str(povm_type)))
def create_from_dmvecs(superket_vectors, povm_type, basis='pp', evotype='default', state_space=None, on_construction_error='warn'): """ TODO: docstring -- create a POVM from a list/dict of (key, pure-vector) pairs """ povm_type_preferences = (povm_type,) if isinstance(povm_type, str) else povm_type if not isinstance(superket_vectors, dict): # then assume it's a list of (key, value) pairs superket_vectors = _collections.OrderedDict(superket_vectors) for typ in povm_type_preferences: try: if typ in ("full", "static"): effects = [(lbl, create_effect_from_dmvec(dmvec, typ, basis, evotype, state_space)) for lbl, dmvec in superket_vectors.items()] povm = UnconstrainedPOVM(effects, evotype, state_space) elif typ == 'full TP': effects = [(lbl, create_effect_from_dmvec(dmvec, 'full', basis, evotype, state_space)) for lbl, dmvec in superket_vectors.items()] povm = TPPOVM(effects, evotype, state_space) elif _ot.is_valid_lindblad_paramtype(typ): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp base_povm = create_from_dmvecs(superket_vectors, ('computational', 'static'), basis, evotype, state_space) proj_basis = 'PP' if state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator(state_space.dim, typ, proj_basis, basis, truncate=True, evotype=evotype, state_space=state_space) povm = ComposedPOVM(_ExpErrorgenOp(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() for k, superket in superket_vectors.items()} povm = create_from_pure_vectors(pure_vectors, typ, basis, evotype, state_space) else: raise ValueError("Unknown POVM type '%s'!" % str(typ)) return povm # if we get to here, then we've successfully created a state to return except (ValueError, AssertionError) as err: if on_construction_error == 'raise': raise err elif on_construction_error == 'warn': print('Failed to construct povm with type "{}" with error: {}'.format(typ, str(err))) pass # move on to next type raise ValueError("Could not create a POVM of type(s) %s from the given pure vectors!" % (str(povm_type)))
def create_effect_from_dmvec(superket_vector, effect_type, basis='pp', evotype='default', state_space=None, on_construction_error='warn'): effect_type_preferences = (effect_type,) if isinstance(effect_type, str) else effect_type if state_space is None: state_space = _statespace.default_space_for_dim(len(superket_vector)) for typ in effect_type_preferences: try: if typ == "static": ef = StaticPOVMEffect(superket_vector, evotype, state_space) elif typ == "full": ef = FullPOVMEffect(superket_vector, evotype, state_space) elif _ot.is_valid_lindblad_paramtype(typ): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp try: dmvec = _bt.change_basis(superket_vector, basis, 'std') purevec = _ot.dmvec_to_state(dmvec) # raises error if dmvec does not correspond to a pure state static_effect = StaticPOVMPureEffect(purevec, basis, evotype, state_space) except ValueError: static_effect = StaticPOVMEffect(superket_vector, evotype, state_space) proj_basis = 'PP' if state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator(state_space.dim, typ, proj_basis, basis, truncate=True, evotype=evotype) ef = ComposedPOVMEffect(static_effect, _ExpErrorgenOp(errorgen)) else: # Anything else we try to convert to a pure vector and convert the pure state vector dmvec = _bt.change_basis(superket_vector, basis, 'std') purevec = _ot.dmvec_to_state(dmvec) # raises error if dmvec does not correspond to a pure state ef = create_effect_from_pure_vector(purevec, typ, basis, evotype, state_space) return ef except (ValueError, AssertionError) as err: if on_construction_error == 'raise': raise err elif on_construction_error == 'warn': print('Failed to construct effect with type "{}" with error: {}'.format(typ, str(err))) pass # move on to next type raise ValueError("Could not create an effect of type(s) %s from the given superket vector!" % (str(effect_type)))
def convert_errorgen(errorgen, to_type, basis, flatten_structure=False): """ TODO: docstring """ to_types = verbose_type_from_op_type(to_type) error_msgs = {} for to_type in to_types: try: if not flatten_structure and isinstance(errorgen, (ComposedErrorgen, EmbeddedErrorgen)): def convert_errorgen_structure(eg): if isinstance(eg, ComposedErrorgen): return ComposedErrorgen([convert_errorgen_structure(f) for f in eg.factors], eg.evotype, eg.state_space) elif isinstance(eg, EmbeddedErrorgen): return EmbeddedErrorgen(eg.state_space, eg.target_labels, convert_errorgen_structure(eg.embedded_op)) else: return convert_errorgen(eg) return convert_errorgen_structure(errorgen) elif isinstance(errorgen, LindbladErrorgen) and _ot.is_valid_lindblad_paramtype(to_type): # Convert the *parameterizations* of block only -- just use to_type as a lookup for # how to convert any blocks of each type (don't require all objects being converted have # all & exactly the Lindbald coefficient block types in `to_type`) to_type = LindbladParameterization.cast(to_type) block_param_conversion = {blk_type: param_mode for blk_type, param_mode in zip(to_type.block_types, to_type.param_modes)} converted_blocks = [blk.convert(block_param_conversion.get(blk._block_type, blk._param_mode)) for blk in errorgen.coefficient_blocks] return LindbladErrorgen(converted_blocks, 'auto', errorgen.matrix_basis, errorgen.evotype, errorgen.state_space) else: raise ValueError("%s is not a valid error generator type!" % str(to_type)) except Exception as e: error_msgs[to_type] = str(e) # try next to_type raise ValueError("Could not convert error generator to type(s): %s\n%s" % (str(to_types), str(error_msgs)))
def convert(operation, to_type, basis, ideal_operation=None, flatten_structure=False): """ Convert operation to a new type of parameterization. This potentially creates a new LinearOperator object, and Raises ValueError for invalid conversions. Parameters ---------- operation : LinearOperator LinearOperator to convert to_type : {"full","full TP","static","static unitary","clifford",LINDBLAD} The type of parameterizaton to convert to. "LINDBLAD" is a placeholder for the various Lindblad parameterization types. See :method:`Model.set_all_parameterizations` for more details. basis : {'std', 'gm', 'pp', 'qt'} or Basis object The basis for `operation`. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). ideal_operation : LinearOperator or "identity", optional The ideal (usually unitary) version of `operation`, potentially used when converting to an error-generator type. The special value `"identity"` can be used to indicate that the ideal operation is the identity. flatten_structure : bool, optional When `False`, the sub-members of composed and embedded operations are separately converted, leaving the original operation's structure unchanged. When `True`, composed and embedded operations are "flattened" into a single operation of the requested `to_type`. Returns ------- LinearOperator The converted operation, usually a distinct object from the operation object passed as input. """ to_types = verbose_type_from_op_type(to_type) error_msgs = {} destination_types = {'full': FullArbitraryOp, 'full TP': FullTPOp, 'linear': LinearlyParamArbitraryOp, 'static': StaticArbitraryOp, 'static unitary': StaticUnitaryOp, 'static clifford': StaticCliffordOp} NoneType = type(None) for to_type in to_types: is_errorgen_type = _ot.is_valid_lindblad_paramtype(to_type) # whether to_type specifies a type of errorgen try: if isinstance(operation, destination_types.get(to_type, NoneType)): return operation if not flatten_structure and isinstance(operation, (ComposedOp, EmbeddedOp)): def convert_structure(op): if isinstance(op, ComposedOp): return ComposedOp([convert_structure(f) for f in op.factorops], op.evotype, op.state_space) elif isinstance(op, EmbeddedOp): return EmbeddedOp(op.state_space, op.target_labels, convert_structure(op.embedded_op)) else: return convert(op, to_type, basis, None, flatten_structure) return convert_structure(operation) elif isinstance(operation, ExpErrorgenOp) and is_errorgen_type: # Just an error generator type conversion return ExpErrorgenOp(convert_errorgen(operation.errorgen, to_type, basis, flatten_structure)) elif (_ot.is_valid_lindblad_paramtype(to_type) and (ideal_operation is not None or operation.num_params == 0)): # e.g. TP -> Lindblad # Above: consider "isinstance(operation, StaticUnitaryOp)" instead of num_params == 0? #Convert a non-exp(errorgen) op to exp(errorgen) * ideal proj_basis = 'PP' if operation.state_space.is_entirely_qubits else basis if ideal_operation == "identity": # special value postfactor_op = None error_map_mx = operation.to_dense('HilbertSchmidt') # error generators are only in HS space else: postfactor_op = ideal_operation if (ideal_operation is not None) else operation error_map_mx = _np.dot(operation.to_dense('HilbertSchmidt'), _np.linalg.inv(postfactor_op.to_dense('HilbertSchmidt'))) errorgen = LindbladErrorgen.from_operation_matrix(error_map_mx, to_type, proj_basis, mx_basis=basis, truncate=True, evotype=operation.evotype, state_space=operation.state_space) ret = ComposedOp([postfactor_op.copy(), ExpErrorgenOp(errorgen)]) \ if (postfactor_op is not None) else ExpErrorgenOp(errorgen) if ret.dim <= 16: # only do this for up to 2Q operations, otherwise to_dense is too expensive assert(_np.linalg.norm(operation.to_dense('HilbertSchmidt') - ret.to_dense('HilbertSchmidt')) < 1e-6), "Failure to create CPTP operation (maybe due the complex log's branch cut?)" return ret else: min_space = operation.evotype.minimal_space mx = operation.to_dense(min_space) if min_space == 'Hilbert': return create_from_unitary_mx(mx, to_type, basis, None, operation.evotype, operation.state_space) else: return create_from_superop_mx(mx, to_type, basis, None, operation.evotype, operation.state_space) except Exception as e: error_msgs[to_type] = str(e) # try next to_type raise ValueError("Could not convert operation to to type(s): %s\n%s" % (str(to_types), str(error_msgs)))
def convert(state, to_type, basis, ideal_state=None, flatten_structure=False): """ TODO: update docstring Convert SPAM vector to a new type of parameterization. This potentially creates a new State object. Raises ValueError for invalid conversions. Parameters ---------- state : State State vector to convert to_type : {"full","full TP","static","static unitary","clifford",LINDBLAD} The type of parameterizaton to convert to. "LINDBLAD" is a placeholder for the various Lindblad parameterization types. See :method:`Model.set_all_parameterizations` for more details. basis : {'std', 'gm', 'pp', 'qt'} or Basis object The basis for `state`. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). ideal_state : State, optional The ideal (usually pure) version of `state`, potentially used when converting to an error-generator type. flatten_structure : bool, optional When `False`, the sub-members of composed and embedded operations are separately converted, leaving the original state's structure unchanged. When `True`, composed and embedded operations are "flattened" into a single state of the requested `to_type`. Returns ------- State The converted State vector, usually a distinct object from the object passed as input. """ to_types = to_type if isinstance(to_type, (tuple, list)) else ( to_type, ) # HACK to support multiple to_type values error_msgs = {} destination_types = { 'full': FullState, 'full TP': TPState, 'TrueCPTP': CPTPState, 'static': StaticState, 'static unitary': StaticPureState, 'static clifford': ComputationalBasisState } NoneType = type(None) for to_type in to_types: try: if isinstance(state, destination_types.get(to_type, NoneType)): return state if not flatten_structure and isinstance(state, ComposedState): return ComposedState( state.state_vec.copy( ), # don't convert (usually static) state vec _mm.operations.convert(state.error_map, to_type, basis, "identity", flatten_structure)) elif _ot.is_valid_lindblad_paramtype(to_type) and ( ideal_state is not None or state.num_params == 0): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp st = ideal_state if (ideal_state is not None) else state proj_basis = 'PP' if state.state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator( state.state_space.dim, to_type, proj_basis, basis, truncate=True, evotype=state.evotype) if st is not state and not _np.allclose( st.to_dense(), state.to_dense()): #Need to set errorgen so exp(errorgen)|st> == |state> dense_st = st.to_dense() dense_state = state.to_dense() def _objfn(v): errorgen.from_vector(v) return _np.linalg.norm( _spl.expm(errorgen.to_dense()) @ dense_st - dense_state) #def callback(x): print("callbk: ",_np.linalg.norm(x),_objfn(x)) # REMOVE soln = _spo.minimize(_objfn, _np.zeros(errorgen.num_params, 'd'), method="CG", options={}, tol=1e-8) # , callback=callback) #print("DEBUG: opt done: ",soln.success, soln.fun, soln.x) # REMOVE if not soln.success and soln.fun > 1e-6: # not "or" because success is often not set correctly raise ValueError( "Failed to find an errorgen such that exp(errorgen)|ideal> = |state>" ) errorgen.from_vector(soln.x) return ComposedState(st, _ExpErrorgenOp(errorgen)) else: min_space = state.evotype.minimal_space vec = state.to_dense(min_space) if min_space == 'Hilbert': return create_from_pure_vector( vec, to_type, basis, state.evotype, state.state_space, on_construction_error='raise') else: return create_from_dmvec(vec, to_type, basis, state.evotype, state.state_space) except ValueError as e: #_warnings.warn('Failed to convert state to type %s with error: %s' % (to_type, e)) error_msgs[to_type] = str(e) # try next to_type raise ValueError("Could not convert state to to type(s): %s\n%s" % (str(to_types), str(error_msgs)))
def convert_effect(effect, to_type, basis, ideal_effect=None, flatten_structure=False): """ TODO: update docstring Convert POVM effect vector to a new type of parameterization. This potentially creates a new POVMEffect object. Raises ValueError for invalid conversions. Parameters ---------- effect : POVMEffect POVM effect vector to convert to_type : {"full","TP","static","static pure","clifford",LINDBLAD} The type of parameterizaton to convert to. "LINDBLAD" is a placeholder for the various Lindblad parameterization types. See :method:`Model.set_all_parameterizations` for more details. basis : {'std', 'gm', 'pp', 'qt'} or Basis object The basis for `spamvec`. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). extra : object, optional Additional information for conversion. Returns ------- POVMEffect The converted POVM effect vector, usually a distinct object from the object passed as input. """ to_types = to_type if isinstance(to_type, (tuple, list)) else (to_type,) # HACK to support multiple to_type values destination_types = {'full': FullPOVMEffect, 'static': StaticPOVMEffect, #'static pure': StaticPOVMPureEffect, 'static clifford': ComputationalBasisPOVMEffect} NoneType = type(None) for to_type in to_types: try: if isinstance(effect, destination_types.get(to_type, NoneType)): return effect if not flatten_structure and isinstance(effect, ComposedPOVMEffect): return ComposedPOVMEffect(effect.effect_vec.copy(), # don't convert (usually static) effect vec _mm.operations.convert(effect.error_map, to_type, basis, "identity", flatten_structure)) elif _ot.is_valid_lindblad_paramtype(to_type) and (ideal_effect is not None or effect.num_params == 0): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp ef = ideal_effect if (ideal_effect is not None) else effect if ef is not effect and not _np.allclose(ef.to_dense(), effect.to_dense()): raise NotImplementedError("Must supply ideal or a static effect to convert to a Lindblad type!") proj_basis = 'PP' if effect.state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator(effect.state_space.dim, to_type, proj_basis, basis, truncate=True, evotype=effect.evotype) return ComposedPOVMEffect(ef, _ExpErrorgenOp(errorgen)) else: min_space = effect.evotype.minimal_space vec = effect.to_dense(min_space) if min_space == 'Hilbert': return create_effect_from_pure_vector(vec, to_type, basis, effect.evotype, effect.state_space, on_construction_error='raise') else: return create_effect_from_dmvec(vec, to_type, basis, effect.evotype, effect.state_space) except ValueError: pass raise ValueError("Could not convert effect to type(s): %s" % str(to_types))
def convert(povm, to_type, basis, ideal_povm=None, flatten_structure=False): """ TODO: update docstring Convert a POVM to a new type of parameterization. This potentially creates a new object. Raises ValueError for invalid conversions. Parameters ---------- povm : POVM POVM to convert to_type : {"full","full TP","static","static pure","H+S terms", "H+S clifford terms","clifford"} The type of parameterizaton to convert to. See :method:`Model.set_all_parameterizations` for more details. TODO docstring: update the options here. basis : {'std', 'gm', 'pp', 'qt'} or Basis object The basis for `povm`. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). ideal_povm : POVM, optional The ideal version of `povm`, potentially used when converting to an error-generator type. flatten_structure : bool, optional When `False`, the sub-members of composed and embedded operations are separately converted, leaving the original POVM's structure unchanged. When `True`, composed and embedded operations are "flattened" into a single POVM of the requested `to_type`. Returns ------- POVM The converted POVM vector, usually a distinct object from the object passed as input. """ to_types = to_type if isinstance(to_type, (tuple, list)) else (to_type,) # HACK to support multiple to_type values error_msgs = {} destination_types = {'full TP': TPPOVM, 'static clifford': ComputationalBasisPOVM} NoneType = type(None) for to_type in to_types: try: if isinstance(povm, destination_types.get(to_type, NoneType)): return povm idl = dict(ideal_povm.items()) if ideal_povm is not None else {} # ideal effects if to_type in ("full", "static", "static pure"): converted_effects = [(lbl, convert_effect(vec, to_type, basis, idl.get(lbl, None), flatten_structure)) for lbl, vec in povm.items()] return UnconstrainedPOVM(converted_effects, povm.evotype, povm.state_space) elif to_type == "full TP": converted_effects = [(lbl, convert_effect(vec, "full", basis, idl.get(lbl, None), flatten_structure)) for lbl, vec in povm.items()] return TPPOVM(converted_effects, povm.evotype, povm.state_space) elif _ot.is_valid_lindblad_paramtype(to_type): from ..operations import LindbladErrorgen as _LindbladErrorgen, ExpErrorgenOp as _ExpErrorgenOp #Construct a static "base" POVM if isinstance(povm, ComputationalBasisPOVM): # special easy case base_povm = ComputationalBasisPOVM(povm.state_space.num_qubits, povm.evotype) # just copy it? else: try: if povm.evotype.minimal_space == 'Hilbert': base_items = [(lbl, convert_effect(vec, 'static pure', basis, idl.get(lbl, None), flatten_structure)) for lbl, vec in povm.items()] else: raise RuntimeError('Evotype must be compatible with Hilbert ops to use pure effects') except Exception: # try static mixed states next: base_items = [(lbl, convert_effect(vec, 'static', basis, idl.get(lbl, None), flatten_structure)) for lbl, vec in povm.items()] base_povm = UnconstrainedPOVM(base_items, povm.evotype, povm.state_space) proj_basis = 'PP' if povm.state_space.is_entirely_qubits else basis errorgen = _LindbladErrorgen.from_error_generator(povm.state_space.dim, to_type, proj_basis, basis, truncate=True, evotype=povm.evotype) return ComposedPOVM(_ExpErrorgenOp(errorgen), base_povm, mx_basis=basis) elif to_type == "static clifford": #Assume `povm` already represents state-vec ops, since otherwise we'd # need to change dimension nqubits = int(round(_np.log2(povm.dim))) #Check if `povm` happens to be a Z-basis POVM on `nqubits` v = (_np.array([1, 0], 'd'), _np.array([0, 1], 'd')) # (v0,v1) - eigenstates of sigma_z for zvals, lbl in zip(_itertools.product(*([(0, 1)] * nqubits)), povm.keys()): testvec = _functools.reduce(_np.kron, [v[i] for i in zvals]) if not _np.allclose(testvec, povm[lbl].to_dense()): raise ValueError("Cannot convert POVM into a Z-basis stabilizer state POVM") #If no errors, then return a stabilizer POVM return ComputationalBasisPOVM(nqubits, 'stabilizer') else: raise ValueError("Invalid to_type argument: %s" % to_type) except Exception as e: error_msgs[to_type] = str(e) # try next to_type raise ValueError("Could not convert POVM to to type(s): %s\n%s" % (str(to_types), str(error_msgs)))