Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add general SaveState instruction #1164

Merged
merged 5 commits into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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