diff --git a/releasenotes/notes/fix-diagonal-unitary-check-a726500ffda6c74b.yaml b/releasenotes/notes/fix-diagonal-unitary-check-a726500ffda6c74b.yaml new file mode 100644 index 0000000000..0220aaef1b --- /dev/null +++ b/releasenotes/notes/fix-diagonal-unitary-check-a726500ffda6c74b.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fix issue where the "diagonal" gate is checked to be unitary with too + high a tolerance. This was causing diagonals generated from Numpy functions + to often fail the test. diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 8620cc493b..a7c55d951f 100755 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -681,7 +681,7 @@ Op json_to_op_diagonal(const json_t &js) { throw std::invalid_argument("\"diagonal\" matrix is wrong size."); } for (const auto val : op.params) { - if (!Linalg::almost_equal(std::abs(val), 1.0)) { + if (!Linalg::almost_equal(std::abs(val), 1.0, 1e-7)) { throw std::invalid_argument("\"diagonal\" matrix is not unitary."); } } diff --git a/test/terra/backends/qasm_simulator/qasm_unitary_gate.py b/test/terra/backends/qasm_simulator/qasm_unitary_gate.py index 8932277527..c2452e7549 100644 --- a/test/terra/backends/qasm_simulator/qasm_unitary_gate.py +++ b/test/terra/backends/qasm_simulator/qasm_unitary_gate.py @@ -72,17 +72,3 @@ def test_diagonal_gate(self): result = execute(circuits, self.SIMULATOR, shots=shots).result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) - - def test_diagonal_gate_wrapper(self): - """Test simulation with unitary gate circuit instructions.""" - shots = 100 - lsts = [ - [1, -1], - [1, -1, -1, 1], - [1.0, -1.0, -1.0, 1.0]] - circuits = [ ref_diagonal_gate.diagonal_gate_circuits_deterministic_w(state) - for state in [ np.array(lst, dtype=t) - for t in (None, float, np.float32, complex, np.complex64) - for lst in lsts ] ] - result = execute(circuits, self.SIMULATOR, shots=shots).result() - self.assertTrue(getattr(result, 'success', False)) diff --git a/test/terra/reference/ref_diagonal_gate.py b/test/terra/reference/ref_diagonal_gate.py index 34c6d3d871..e3d9b6213f 100644 --- a/test/terra/reference/ref_diagonal_gate.py +++ b/test/terra/reference/ref_diagonal_gate.py @@ -22,25 +22,6 @@ if not hasattr(QuantumCircuit, 'diagonal'): QuantumCircuit.diagonal = QuantumCircuit.diag_gate -def diagonal_gate_circuits_deterministic_w(state, final_measure=True): - """Diagonal gate test circuits with deterministic count output.""" - - qr = QuantumRegister(2, 'qr') - if final_measure: - cr = ClassicalRegister(2, 'cr') - regs = (qr, cr) - else: - regs = (qr, ) - - # Swap |00> <--> |11> states - circuit = QuantumCircuit(*regs) - circuit.h(qr) - circuit.diagonal([1, -1, -1, 1], qr) - circuit.h(qr) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - return circuit def diagonal_gate_circuits_deterministic(final_measure=True): """Diagonal gate test circuits with deterministic count output.""" @@ -53,44 +34,42 @@ def diagonal_gate_circuits_deterministic(final_measure=True): else: regs = (qr, ) - # Swap |00> <--> |01> states - circuit = QuantumCircuit(*regs) - circuit.h(0) - circuit.diagonal([1, -1], [0]) - circuit.h(0) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # Swap |00> <--> |10> states - circuit = QuantumCircuit(*regs) - circuit.h(1) - circuit.diagonal([1, -1], [1]) - circuit.h(1) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # Swap |00> <--> |11> states - circuit = QuantumCircuit(*regs) - circuit.h(qr) - circuit.diagonal([1, -1, -1, 1], qr) - circuit.h(qr) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # CS01.XX, 1j|11> state - circuit = QuantumCircuit(*regs) - circuit.x(qr) - circuit.diagonal([1, 1, 1, 1j], qr) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) + # 4 x Swap |00> <--> |01> states + # 4 x Swap |00> <--> |10> states + arg = [1, -1] + for qubit in [0, 1]: + for diag in [arg, np.array(arg), np.array(arg, dtype=float), np.array(arg, dtype=complex)]: + circuit = QuantumCircuit(*regs) + circuit.h(qubit) + circuit.diagonal(list(diag), [qubit]) + circuit.h(qubit) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # 4 x Swap |00> <--> |11> states + arg = [1, -1, -1, 1] + for diag in [arg, np.array(arg), np.array(arg, dtype=float), np.array(arg, dtype=complex)]: + circuit = QuantumCircuit(*regs) + circuit.h(qr) + circuit.diagonal(list(diag), qr) + circuit.h(qr) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # CS01.XX, exp(-1j * np.pi/k)|11> state + for diag in [np.array([1, 1, 1, np.exp(-1j * np.pi / k)]) + for k in [10, 100, 1000, 10000]]: + circuit = QuantumCircuit(*regs) + circuit.x(qr) + circuit.diagonal(list(diag), qr) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) return circuits @@ -100,22 +79,22 @@ def diagonal_gate_counts_deterministic(shots, hex_counts=True): targets = [] if hex_counts: # Swap |00> <--> |01> states - targets.append({'0x1': shots}) + targets += 4 * [{'0x1': shots}] # Swap |00> <--> |10> states - targets.append({'0x2': shots}) + targets += 4 * [{'0x2': shots}] # Swap |00> <--> |11> states - targets.append({'0x3': shots}) - # CS01.XX, 1j|11> state - targets.append({'0x3': shots}) + targets += 4 * [{'0x3': shots}] + # CS01.XX, exp(-1j * np.pi/N)|11> state + targets += 4 * [{'0x3': shots}] else: # Swap |00> <--> |01> states - targets.append({'01': shots}) + targets += 4 * [{'01': shots}] # Swap |00> <--> |10> states - targets.append({'10': shots}) + targets += 4 * [{'10': shots}] # Swap |00> <--> |11> states - targets.append({'11': shots}) - # CS01.XX, 1j|11> state - targets.append({'11': shots}) + targets += 4 * [{'11': shots}] + # CS01.XX, exp(-1j * np.pi/k)|11> state + targets += 4 * [{'11': shots}] return targets @@ -123,13 +102,13 @@ def diagonal_gate_statevector_deterministic(): """Diagonal gate test circuits with deterministic counts.""" targets = [] # Swap |00> <--> |01> states - targets.append(np.array([0, 1, 0, 0])) + targets += 4 * [np.array([0, 1, 0, 0])] # Swap |00> <--> |10> states - targets.append(np.array([0, 0, 1, 0])) + targets += 4 * [np.array([0, 0, 1, 0])] # Swap |00> <--> |11> states - targets.append(np.array([0, 0, 0, 1])) - # CS01.XX, 1j|11> state - targets.append(np.array([0, 0, 0, 1j])) + targets += 4 * [np.array([0, 0, 0, 1])] + # CS01.XX, exp(-1j * np.pi/k)|11> state + targets += [np.array([0, 0, 0, np.exp(-1j * np.pi / k)]) for k in [10, 100, 1000, 10000]] return targets @@ -138,23 +117,24 @@ def diagonal_gate_unitary_deterministic(): targets = [] # Swap |00> <--> |01> states - targets.append(np.array([[0, 1, 0, 0], - [1, 0, 0, 0], - [0, 0, 0, 1], - [0, 0, 1, 0]])) + targets += 4 * [np.array([[0, 1, 0, 0], + [1, 0, 0, 0], + [0, 0, 0, 1], + [0, 0, 1, 0]])] # Swap |00> <--> |10> states - targets.append(np.array([[0, 0, 1, 0], - [0, 0, 0, 1], - [1, 0, 0, 0], - [0, 1, 0, 0]])) + targets += 4 * [np.array([[0, 0, 1, 0], + [0, 0, 0, 1], + [1, 0, 0, 0], + [0, 1, 0, 0]])] # Swap |00> <--> |11> states - targets.append(np.array([[0, 0, 0, 1], - [0, 0, 1, 0], - [0, 1, 0, 0], - [1, 0, 0, 0]])) + targets += 4 * [np.array([[0, 0, 0, 1], + [0, 0, 1, 0], + [0, 1, 0, 0], + [1, 0, 0, 0]])] # CS01.XX, 1j|11> state - targets.append(np.array([[0, 0, 0, 1], - [0, 0, 1, 0], - [0, 1, 0, 0], - [1j, 0, 0, 0]])) + targets += [np.array([[0, 0, 0, 1], + [0, 0, 1, 0], + [0, 1, 0, 0], + [np.exp(-1j * np.pi / k), 0, 0, 0]]) + for k in [10, 100, 1000, 10000]] return targets