Skip to content

Commit

Permalink
Add general SaveState instruction (#1164)
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseclectic authored Mar 16, 2021
1 parent 1994b35 commit 7e6ed61
Show file tree
Hide file tree
Showing 17 changed files with 335 additions and 31 deletions.
8 changes: 4 additions & 4 deletions qiskit/providers/aer/backends/qasm_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,14 +295,14 @@ class QasmSimulator(AerBackend):
'initialize', 'delay', 'pauli', 'mcx_gray',
# Custom instructions
'kraus', 'roerror', 'snapshot', 'save_expval', 'save_expval_var',
'save_probabilities', 'save_probabilities_dict',
'save_probabilities', 'save_probabilities_dict', 'save_state',
'save_density_matrix', 'save_statevector',
'save_amplitudes', 'save_amplitudes_sq', 'save_stabilizer'
]),
'custom_instructions': sorted([
'roerror', 'kraus', 'snapshot', 'save_expval', 'save_expval_var',
'save_probabilities', 'save_probabilities_dict',
'save_density_matrix', 'save_statevector',
'save_state', 'save_density_matrix', 'save_statevector',
'save_amplitudes', 'save_amplitudes_sq', 'save_stabilizer']),
'gates': []
}
Expand Down Expand Up @@ -481,7 +481,7 @@ def _method_configuration(method=None):
config.custom_instructions = sorted([
'roerror', 'snapshot', 'kraus', 'superop', 'save_expval', 'save_expval_var',
'save_probabilities', 'save_probabilities_dict', 'save_density_matrix',
'save_amplitudes_sq'])
'save_amplitudes_sq', 'save_state'])
config.basis_gates = sorted([
'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x',
'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx',
Expand Down Expand Up @@ -511,7 +511,7 @@ def _method_configuration(method=None):
config.custom_instructions = sorted([
'roerror', 'snapshot', 'save_expval', 'save_expval_var',
'save_probabilities', 'save_probabilities_dict',
'save_amplitudes_sq', 'save_stabilizer'])
'save_amplitudes_sq', 'save_stabilizer', 'save_state'])
config.basis_gates = sorted([
'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 'cx', 'cy', 'cz',
'swap', 'delay',
Expand Down
2 changes: 1 addition & 1 deletion qiskit/providers/aer/backends/statevector_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class StatevectorSimulator(AerBackend):
'initialize', 'kraus', 'roerror', 'delay', 'pauli',
'save_expval', 'save_density_matrix', 'save_statevector',
'save_probs', 'save_probs_ket', 'save_amplitudes',
'save_amplitudes_sq'
'save_amplitudes_sq', 'save_state'
],
'gates': []
}
Expand Down
2 changes: 1 addition & 1 deletion qiskit/providers/aer/backends/unitary_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class UnitarySimulator(AerBackend):
'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx',
'mcp', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz',
'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'delay', 'pauli',
'save_unitary'
'save_unitary', 'save_state'
],
'gates': []
}
Expand Down
10 changes: 7 additions & 3 deletions qiskit/providers/aer/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
.. autosummary::
:toctree: ../stubs/
SaveState
SaveExpectationValue
SaveExpectationValueVariance
SaveProbabilities
Expand All @@ -53,6 +54,7 @@
.. autosummary::
:toctree: ../stubs/
save_state
save_expectation_value
save_expectation_value_variance
save_probabilities
Expand Down Expand Up @@ -95,12 +97,14 @@
state.
"""

__all__ = ['SaveExpectationValue', 'SaveExpectationValueVariance',
__all__ = ['SaveState',
'SaveExpectationValue', 'SaveExpectationValueVariance',
'SaveProbabilities', 'SaveProbabilitiesDict',
'SaveStatevector', 'SaveStatevectorDict', 'SaveDensityMatrix',
'SaveAmplitudes', 'SaveAmplitudesSquared', 'SaveUnitary',
'SaveStabilizer']

from .save_state import SaveState, save_state
from .save_expectation_value import (
SaveExpectationValue, save_expectation_value,
SaveExpectationValueVariance, save_expectation_value_variance)
Expand All @@ -111,5 +115,5 @@
from .save_density_matrix import SaveDensityMatrix, save_density_matrix
from .save_amplitudes import (SaveAmplitudes, save_amplitudes,
SaveAmplitudesSquared, save_amplitudes_squared)
from .save_stabilizer import (SaveStabilizer, save_stabilizer)
from .save_unitary import (SaveUnitary, save_unitary)
from .save_stabilizer import SaveStabilizer, save_stabilizer
from .save_unitary import SaveUnitary, save_unitary
85 changes: 85 additions & 0 deletions qiskit/providers/aer/library/save_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
Simulator instruction to save simulator state.
"""

from qiskit.circuit import QuantumCircuit
from .save_data import SaveSingleData, default_qubits


class SaveState(SaveSingleData):
"""Save simulator state
The format of the saved state depends on the simulation method used.
"""
def __init__(self, num_qubits,
label=None,
pershot=False,
conditional=False):
"""Create new instruction to save the simualtor state.
The format of the saved state depends on the simulation method used.
Args:
num_qubits (int): the number of qubits of the
label (str or None): Optional, the key for retrieving saved data
from results. If None the key will be the
state type of the simulator.
pershot (bool): if True save a list of states for each
shot of the simulation rather than a single
state [Default: False].
conditional (bool): if True save data conditional on the current
classical register values [Default: False].
.. note::
This save instruction must always be performed on the full width of
qubits in a circuit, otherwise an exception will be raised during
simulation.
"""
if label is None:
label = '_method_'
super().__init__('save_state', num_qubits, label,
pershot=pershot,
conditional=conditional)


def save_state(self, label=None, pershot=False, conditional=False):
"""Save the current simulator quantum state.
Args:
label (str or None): Optional, the key for retrieving saved data
from results. If None the key will be the
state type of the simulator.
pershot (bool): if True save a list of statevectors for each
shot of the simulation [Default: False].
conditional (bool): if True save pershot data conditional on the
current classical register values
[Default: False].
Returns:
QuantumCircuit: with attached instruction.
.. note:
This instruction is always defined across all qubits in a circuit.
"""
qubits = default_qubits(self)
instr = SaveState(len(qubits),
label=label,
pershot=pershot,
conditional=conditional)
return self.append(instr, qubits)


QuantumCircuit.save_state = save_state
10 changes: 10 additions & 0 deletions releasenotes/notes/save-data-instructions-24b127612c9f6502.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,13 @@ features:
This instruction can also be appended to a quantum circuit by using the
:class:`~qiskit.providers.aer.library.save_unitary`` circuit
methods which is added to ``QuantumCircuit`` when importing Aer.
- |
Adds a :class:`qiskit.providers.aer.library.SaveState`
circuit instruction for saving the state of the
:class:`~qiskit.providers.aer.QasmSimulator`. The format of the saved
state depends on the simulation method
(eg. statevector, density matrix, etc).
This instruction can also be appended to a quantum circuit by using the
:class:`~qiskit.providers.aer.library.save_state`` circuit
methods which is added to ``QuantumCircuit`` when importing Aer.
9 changes: 7 additions & 2 deletions src/framework/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ enum class OpType {
// Noise instructions
kraus, superop, roerror, noise_switch,
// Save instructions
save_expval, save_expval_var, save_statevec, save_statevec_ket,
save_state, save_expval, save_expval_var, save_statevec, save_statevec_ket,
save_densmat, save_probs, save_probs_ket, save_amps, save_amps_sq,
save_stabilizer, save_unitary
};
Expand All @@ -51,7 +51,7 @@ enum class DataSubType {
};

static const std::unordered_set<OpType> SAVE_TYPES = {
OpType::save_expval, OpType::save_expval_var,
OpType::save_state, OpType::save_expval, OpType::save_expval_var,
OpType::save_statevec, OpType::save_statevec_ket,
OpType::save_densmat, OpType::save_probs, OpType::save_probs_ket,
OpType::save_amps, OpType::save_amps_sq, OpType::save_stabilizer,
Expand All @@ -75,6 +75,9 @@ inline std::ostream& operator<<(std::ostream& stream, const OpType& type) {
case OpType::barrier:
stream << "barrier";
break;
case OpType::save_state:
stream << "save_state";
break;
case OpType::save_expval:
stream << "save_expval";
break;
Expand Down Expand Up @@ -515,6 +518,8 @@ Op json_to_op(const json_t &js) {
if (name == "superop")
return json_to_op_superop(js);
// Save
if (name == "save_state")
return json_to_op_save_default(js, OpType::save_state);
if (name == "save_expval")
return json_to_op_save_expval(js, false);
if (name == "save_expval_var")
Expand Down
48 changes: 47 additions & 1 deletion src/simulators/density_matrix/densitymatrix_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const Operations::OpSet StateOpSet(
OpType::superop, OpType::save_expval,
OpType::save_expval_var, OpType::save_densmat,
OpType::save_probs, OpType::save_probs_ket,
OpType::save_amps_sq
OpType::save_amps_sq, OpType::save_state
},
// Gates
{"U", "CX", "u1", "u2", "u3", "u", "cx", "cy", "cz",
Expand Down Expand Up @@ -189,6 +189,11 @@ class State : public Base::State<densmat_t> {
// Save data instructions
//-----------------------------------------------------------------------

// Save the current full density matrix
void apply_save_state(const Operations::Op &op,
ExperimentResult &result,
bool last_op = false);

// Save the current density matrix or reduced density matrix
void apply_save_density_matrix(const Operations::Op &op,
ExperimentResult &result,
Expand Down Expand Up @@ -489,6 +494,9 @@ void State<densmat_t>::apply_ops(const std::vector<Operations::Op> &ops,
case OpType::save_expval_var:
BaseState::apply_save_expval(op, result);
break;
case OpType::save_state:
apply_save_state(op, result, final_ops && ops.size() == i + 1);
break;
case OpType::save_densmat:
apply_save_density_matrix(op, result, final_ops && ops.size() == i + 1);
break;
Expand Down Expand Up @@ -558,6 +566,44 @@ void State<densmat_t>::apply_save_density_matrix(const Operations::Op &op,
op.save_type);
}

template <class densmat_t>
void State<densmat_t>::apply_save_state(const Operations::Op &op,
ExperimentResult &result,
bool last_op) {
if (op.qubits.size() != BaseState::qreg_.num_qubits()) {
throw std::invalid_argument(
op.name + " was not applied to all qubits."
" Only the full state can be saved.");
}
// Renamp single data type to average
Operations::DataSubType save_type;
switch (op.save_type) {
case Operations::DataSubType::single:
save_type = Operations::DataSubType::average;
break;
case Operations::DataSubType::c_single:
save_type = Operations::DataSubType::c_average;
break;
default:
save_type = op.save_type;
}

// Default key
std::string key = (op.string_params[0] == "_method_")
? "density_matrix"
: op.string_params[0];
if (last_op) {
BaseState::save_data_average(result, key,
BaseState::qreg_.move_to_matrix(),
save_type);
} else {
BaseState::save_data_average(result, key,
BaseState::qreg_.copy_to_matrix(),
save_type);
}
}


template <class densmat_t>
cmatrix_t State<densmat_t>::reduced_density_matrix(const reg_t& qubits, bool last_op) {
cmatrix_t reduced_state;
Expand Down
33 changes: 33 additions & 0 deletions src/simulators/density_matrix/densitymatrix_state_chunk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const Operations::OpSet StateOpSet(
OpType::diagonal_matrix, OpType::kraus,
OpType::superop, OpType::save_expval,
OpType::save_expval_var, OpType::save_densmat,
OpType::save_state,
OpType::save_probs, OpType::save_probs_ket,
OpType::save_amps_sq
},
Expand Down Expand Up @@ -169,6 +170,11 @@ class State : public Base::StateChunk<densmat_t> {
// Save data instructions
//-----------------------------------------------------------------------

// Save the current density matrix
void apply_save_state(const Operations::Op &op,
ExperimentResult &result,
bool last_op = false);

// Save the current density matrix or reduced density matrix
void apply_save_density_matrix(const Operations::Op &op,
ExperimentResult &result,
Expand Down Expand Up @@ -615,6 +621,9 @@ void State<densmat_t>::apply_op(const int_t iChunk,const Operations::Op &op,
case Operations::OpType::save_expval_var:
BaseState::apply_save_expval(op, result);
break;
case Operations::OpType::save_state:
apply_save_state(op, result, final_ops);
break;
case Operations::OpType::save_densmat:
apply_save_density_matrix(op, result, final_ops);
break;
Expand Down Expand Up @@ -812,6 +821,30 @@ void State<densmat_t>::apply_save_density_matrix(const Operations::Op &op,
op.save_type);
}

template <class densmat_t>
void State<densmat_t>::apply_save_state(const Operations::Op &op,
ExperimentResult &result,
bool last_op)
{
// Renamp single data type to average
Operations::Op op_cpy = op;
switch (op.save_type) {
case Operations::DataSubType::single:
op_cpy.save_type = Operations::DataSubType::average;
break;
case Operations::DataSubType::c_single:
op_cpy.save_type = Operations::DataSubType::c_average;
break;
default:
break;
}
// Default key
op_cpy.string_params[0] = (op.string_params[0] == "_method_")
? "density_matrix"
: op.string_params[0];
apply_save_density_matrix(op_cpy, result, last_op);
}

//=========================================================================
// Implementation: Snapshots
//=========================================================================
Expand Down
6 changes: 4 additions & 2 deletions src/simulators/stabilizer/stabilizer_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const Operations::OpSet StateOpSet(
OpType::roerror, OpType::save_expval,
OpType::save_expval_var, OpType::save_probs,
OpType::save_probs_ket, OpType::save_amps_sq,
OpType::save_stabilizer},
OpType::save_stabilizer, OpType::save_state},
// Gates
{"CX", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg",
"sx", "delay"},
Expand Down Expand Up @@ -344,6 +344,7 @@ void State::apply_ops(const std::vector<Operations::Op> &ops,
case OpType::save_amps_sq:
apply_save_amplitudes_sq(op, result);
break;
case OpType::save_state:
case OpType::save_stabilizer:
apply_save_stabilizer(op, result);
break;
Expand Down Expand Up @@ -483,8 +484,9 @@ std::vector<reg_t> State::sample_measure(const reg_t &qubits,

void State::apply_save_stabilizer(const Operations::Op &op,
ExperimentResult &result) {
std::string key = (op.string_params[0] == "_method_") ? "stabilizer" : op.string_params[0];
json_t clifford = BaseState::qreg_;
BaseState::save_data_pershot(result, op.string_params[0],
BaseState::save_data_pershot(result, key,
std::move(clifford), op.save_type);
}

Expand Down
Loading

0 comments on commit 7e6ed61

Please sign in to comment.