def __init__(self, data, input_dims=None, output_dims=None): """Initialize a Stinespring quantum channel operator.""" if issubclass(data.__class__, BaseOperator): # If not a channel we use `to_operator` method to get # the unitary-representation matrix for input if not issubclass(data.__class__, QuantumChannel): data = data.to_operator() input_dim, output_dim = data.dim stine = _to_stinespring(data.rep, data._data, input_dim, output_dim) if input_dims is None: input_dims = data.input_dims() if output_dims is None: output_dims = data.output_dims() elif isinstance(data, (list, tuple, np.ndarray)): if not isinstance(data, tuple): # Convert single Stinespring set to length 1 tuple stine = (np.array(data, dtype=complex), None) if isinstance(data, tuple) and len(data) == 2: if data[1] is None: stine = (np.array(data[0], dtype=complex), None) else: stine = (np.array(data[0], dtype=complex), np.array(data[1], dtype=complex)) dim_left, dim_right = stine[0].shape # If two stinespring matrices check they are same shape if stine[1] is not None: if stine[1].shape != (dim_left, dim_right): raise QiskitError("Invalid Stinespring input.") input_dim = dim_right if output_dims: output_dim = np.product(output_dims) else: output_dim = input_dim if dim_left % output_dim != 0: raise QiskitError("Invalid output_dim") else: raise QiskitError("Invalid input data format for Stinespring") # Check and format input and output dimensions input_dims = self._automatic_dims(input_dims, input_dim) output_dims = self._automatic_dims(output_dims, output_dim) # Initialize either single or general Stinespring if stine[1] is None or (stine[1] == stine[0]).all(): # Standard Stinespring map super().__init__( 'Stinespring', (stine[0], None), input_dims=input_dims, output_dims=output_dims) else: # General (non-CPTP) Stinespring map super().__init__( 'Stinespring', stine, input_dims=input_dims, output_dims=output_dims)
def __init__(self, data, input_dims=None, output_dims=None): """Initialize a quantum channel Stinespring operator. Args: data (QuantumCircuit or Instruction or BaseOperator or matrix): data to initialize superoperator. input_dims (tuple): the input subsystem dimensions. [Default: None] output_dims (tuple): the output subsystem dimensions. [Default: None] Raises: QiskitError: if input data cannot be initialized as a a list of Kraus matrices. Additional Information: If the input or output dimensions are None, they will be automatically determined from the input data. This can fail for the Stinespring operator if the output dimension cannot be automatically determined. """ # If the input is a list or tuple we assume it is a pair of general # Stinespring matrices. If it is a numpy array we assume that it is # a single Stinespring matrix. if isinstance(data, (list, tuple, np.ndarray)): if not isinstance(data, tuple): # Convert single Stinespring set to length 1 tuple stine = (np.asarray(data, dtype=complex), None) if isinstance(data, tuple) and len(data) == 2: if data[1] is None: stine = (np.asarray(data[0], dtype=complex), None) else: stine = (np.asarray(data[0], dtype=complex), np.asarray(data[1], dtype=complex)) dim_left, dim_right = stine[0].shape # If two Stinespring matrices check they are same shape if stine[1] is not None: if stine[1].shape != (dim_left, dim_right): raise QiskitError("Invalid Stinespring input.") input_dim = dim_right if output_dims: output_dim = np.product(output_dims) else: output_dim = input_dim if dim_left % output_dim != 0: raise QiskitError("Invalid output_dim") else: # Otherwise we initialize by conversion from another Qiskit # object into the QuantumChannel. if isinstance(data, (QuantumCircuit, Instruction)): # If the input is a Terra QuantumCircuit or Instruction we # convert it to a SuperOp data = SuperOp._init_instruction(data) else: # We use the QuantumChannel init transform to intialize # other objects into a QuantumChannel or Operator object. data = self._init_transformer(data) data = self._init_transformer(data) input_dim, output_dim = data.dim # Now that the input is an operator we convert it to a # Stinespring operator rep = getattr(data, '_channel_rep', 'Operator') stine = _to_stinespring(rep, data._data, input_dim, output_dim) if input_dims is None: input_dims = data.input_dims() if output_dims is None: output_dims = data.output_dims() # Check and format input and output dimensions input_dims = self._automatic_dims(input_dims, input_dim) output_dims = self._automatic_dims(output_dims, output_dim) # Initialize either single or general Stinespring if stine[1] is None or (stine[1] == stine[0]).all(): # Standard Stinespring map super().__init__((stine[0], None), input_dims=input_dims, output_dims=output_dims, channel_rep='Stinespring') else: # General (non-CPTP) Stinespring map super().__init__(stine, input_dims=input_dims, output_dims=output_dims, channel_rep='Stinespring')