Esempio n. 1
0
    def test_mz_gate_standard(self, tol):
        """Test that the Mach-Zehnder gate compiles to give the correct unitary
        for some specific standard parameters"""
        prog = sf.Program(8)

        with prog.context as q:
            ops.MZgate(np.pi / 2, np.pi) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi / 2, np.pi) | (q[4], q[5])
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MeasureFock() | q

        # compile the program using the X8_01 spec
        res = prog.compile("X8_01")

        # remove the Fock measurements
        res.circuit = res.circuit[:-1]

        # extract the Gaussian symplectic matrix
        O = res.compile("gaussian_unitary").circuit[0].op.p[0]

        # By construction, we know that the symplectic matrix is
        # passive, and so represents a unitary matrix
        U = O[:8, :8] + 1j * O[8:, :8]

        # the constructed program should implement the following
        # unitary matrix
        expected = np.array([[0.5 - 0.5j, -0.5 + 0.5j, 0, 0],
                             [0.5 - 0.5j, 0.5 - 0.5j, 0, 0], [0, 0, -1, -0],
                             [0, 0, -0, 1]])
        expected = block_diag(expected, expected)

        assert np.allclose(U, expected, atol=tol)
Esempio n. 2
0
    def runJob(self, eng):
        num_subsystem = 8
        prog = sf.Program(num_subsystem, name="remote_job")
        U = random_interferometer(4)
        with prog.context as q:
            # Initial squeezed states
            # Allowed values are r=1.0 or r=0.0
            ops.S2gate(1.0) | (q[0], q[4])
            ops.S2gate(1.0) | (q[1], q[5])
            ops.S2gate(1.0) | (q[3], q[7])

            # Interferometer on the signal modes (0-3)
            ops.Interferometer(U) | (q[0], q[1], q[2], q[3])
            ops.BSgate(0.543, 0.123) | (q[2], q[0])
            ops.Rgate(0.453) | q[1]
            ops.MZgate(0.65, -0.54) | (q[2], q[3])

            # *Same* interferometer on the idler modes (4-7)
            ops.Interferometer(U) | (q[4], q[5], q[6], q[7])
            ops.BSgate(0.543, 0.123) | (q[6], q[4])
            ops.Rgate(0.453) | q[5]
            ops.MZgate(0.65, -0.54) | (q[6], q[7])

            ops.MeasureFock() | q


        eng = eng
        results =eng.run(prog, shots=10)
        # state = results.state
        # measurements = results.samples
        return results.samples
Esempio n. 3
0
def test_all_passive_gates(hbar, tol):
    """test that all gates run and do not cause anything to crash"""

    eng = sf.LocalEngine(backend="gaussian")
    circuit = sf.Program(4)

    with circuit.context as q:
        for i in range(4):
            ops.Sgate(1, 0.3) | q[i]
        ops.Rgate(np.pi) | q[0]
        ops.PassiveChannel(np.ones((2, 2))) | (q[1], q[2])
        ops.LossChannel(0.9) | q[1]
        ops.MZgate(0.25 * np.pi, 0) | (q[2], q[3])
        ops.PassiveChannel(np.array([[0.83]])) | q[0]
        ops.sMZgate(0.11, -2.1) | (q[0], q[3])
        ops.Interferometer(np.array([[np.exp(1j * 2)]])) | q[1]
        ops.BSgate(0.8, 0.4) | (q[1], q[3])
        ops.Interferometer(0.5**0.5 * np.fft.fft(np.eye(2))) | (q[0], q[2])
        ops.PassiveChannel(0.1 * np.ones((3, 3))) | (q[3], q[1], q[0])

    cov = eng.run(circuit).state.cov()

    circuit = sf.Program(4)
    with circuit.context as q:
        ops.Rgate(np.pi) | q[0]
        ops.PassiveChannel(np.ones((2, 2))) | (q[1], q[2])
        ops.LossChannel(0.9) | q[1]
        ops.MZgate(0.25 * np.pi, 0) | (q[2], q[3])
        ops.PassiveChannel(np.array([[0.83]])) | q[0]
        ops.sMZgate(0.11, -2.1) | (q[0], q[3])
        ops.Interferometer(np.array([[np.exp(1j * 2)]])) | q[1]
        ops.BSgate(0.8, 0.4) | (q[1], q[3])
        ops.Interferometer(0.5**0.5 * np.fft.fft(np.eye(2))) | (q[0], q[2])
        ops.PassiveChannel(0.1 * np.ones((3, 3))) | (q[3], q[1], q[0])

    compiled_circuit = circuit.compile(compiler="passive")
    T = compiled_circuit.circuit[0].op.p[0]

    S_sq = np.eye(8, dtype=np.complex128)
    r = 1
    phi = 0.3
    for i in range(4):
        S_sq[i, i] = np.cosh(r) - np.sinh(r) * np.cos(phi)
        S_sq[i, i + 4] = -np.sinh(r) * np.sin(phi)
        S_sq[i + 4, i] = -np.sinh(r) * np.sin(phi)
        S_sq[i + 4, i + 4] = np.cosh(r) + np.sinh(r) * np.cos(phi)

    cov_sq = (hbar / 2) * S_sq @ S_sq.T
    mu = np.zeros(8)

    P = interferometer(T)
    L = (hbar / 2) * (np.eye(P.shape[0]) - P @ P.T)
    cov2 = P @ cov_sq @ P.T + L

    assert np.allclose(cov, cov2, atol=tol, rtol=0)
Esempio n. 4
0
    def test_mz_gate_non_standard(self, theta1, phi1, tol):
        """Test that the Mach-Zehnder gate compiles to give the correct unitary
        for a variety of non-standard angles"""
        prog = sf.Program(8)

        theta2 = np.pi / 13
        phi2 = 3 * np.pi / 7

        with prog.context as q:
            ops.MZgate(theta1, phi1) | (q[0], q[1])
            ops.MZgate(theta2, phi2) | (q[2], q[3])
            ops.MZgate(theta1, phi1) | (q[4], q[5])
            ops.MZgate(theta2, phi2) | (q[6], q[7])
            ops.MeasureFock() | q

        # compile the program using the X8_01 spec
        res = prog.compile("X8_01")

        # remove the Fock measurements
        res.circuit = res.circuit[:-1]

        # extract the Gaussian symplectic matrix
        O = res.compile("gaussian_unitary").circuit[0].op.p[0]

        # By construction, we know that the symplectic matrix is
        # passive, and so represents a unitary matrix
        U = O[:8, :8] + 1j * O[8:, :8]

        # the constructed program should implement the following
        # unitary matrix
        expected = np.array([
            [(np.exp(1j * phi1) * (-1 + np.exp(1j * theta1))) / 2.0,
             0.5j * (1 + np.exp(1j * theta1)), 0, 0],
            [
                0.5j * np.exp(1j * phi1) * (1 + np.exp(1j * theta1)),
                (1 - np.exp(1j * theta1)) / 2.0, 0, 0
            ],
            [
                0, 0, (np.exp(1j * phi2) * (-1 + np.exp(1j * theta2))) / 2.0,
                0.5j * (1 + np.exp(1j * theta2))
            ],
            [
                0, 0, 0.5j * np.exp(1j * phi2) * (1 + np.exp(1j * theta2)),
                (1 - np.exp(1j * theta2)) / 2.0
            ],
        ])
        expected = block_diag(expected, expected)

        assert np.allclose(U, expected, atol=tol)
def test_non_primitive_gates():
    """Tests that the compiler is able to compile a number of non-primitive Gaussian gates"""

    width = 6
    eng = sf.LocalEngine(backend="gaussian")
    eng1 = sf.LocalEngine(backend="gaussian")
    circuit = sf.Program(width)
    A = np.random.rand(width, width) + 1j * np.random.rand(width, width)
    A = A + A.T
    valsA = np.linalg.svd(A, compute_uv=False)
    A = A / 2 * np.max(valsA)
    B = np.random.rand(
        width // 2, width // 2) + 1j * np.random.rand(width // 2, width // 2)
    valsB = np.linalg.svd(B, compute_uv=False)
    B = B / 2 * valsB
    B = np.block([[0 * B, B], [B.T, 0 * B]])
    with circuit.context as q:
        ops.GraphEmbed(A) | q
        ops.BipartiteGraphEmbed(B) | q
        ops.Pgate(0.1) | q[1]
        ops.CXgate(0.2) | (q[0], q[1])
        ops.MZgate(0.4, 0.5) | (q[2], q[3])
        ops.Fourier | q[0]
        ops.Xgate(0.4) | q[1]
        ops.Zgate(0.5) | q[3]
    compiled_circuit = circuit.compile(compiler="gaussian_unitary")
    cv = eng.run(circuit).state.cov()
    mean = eng.run(circuit).state.means()

    cv1 = eng1.run(compiled_circuit).state.cov()
    mean1 = eng1.run(compiled_circuit).state.means()
    assert np.allclose(cv, cv1)
    assert np.allclose(mean, mean1)
    def test_MZgate_decomposition(self):
        """Test that decompositions take
        place if the circuit spec requests it."""

        class DummyCircuit(Compiler):
            modes = None
            remote = False
            local = True
            interactive = True
            primitives = {"S2gate", "Interferometer", "BSgate", "Sgate", "MZgate", "Rgate"}
            decompositions = {"MZgate": {}}

        prog = sf.Program(3)
        U = np.array([[0, 1], [1, 0]])
        with prog.context as q:
            ops.MZgate(0.6, 0.7) | [q[0], q[1]]
            ops.Interferometer(U) | [q[0], q[1]]

        new_prog = prog.compile(compiler=DummyCircuit())

        # check compiled program now has 5 gates
        # the MZgate should decompose into two BS and two Rgates
        assert len(new_prog) == 5

        # test gates are correct
        circuit = new_prog.circuit
        assert circuit[0].op.__class__.__name__ == "Rgate"
        assert circuit[1].op.__class__.__name__ == "BSgate"
        assert circuit[2].op.__class__.__name__ == "Rgate"
        assert circuit[3].op.__class__.__name__ == "BSgate"
        assert circuit[4].op.__class__.__name__ == "Interferometer"
    def test_no_decompositions(self):
        """Test that no decompositions take
        place if the circuit spec doesn't support it."""

        class DummyCircuit(Compiler):
            """A circuit spec with no decompositions"""

            modes = None
            remote = False
            local = True
            interactive = True
            primitives = {"S2gate", "Interferometer", "MZgate"}
            decompositions = set()

        prog = sf.Program(3)
        U = np.array([[0, 1], [1, 0]])
        with prog.context as q:
            ops.S2gate(0.6) | [q[0], q[1]]
            ops.Interferometer(U) | [q[0], q[1]]
            ops.MZgate(0.1, 0.6) | [q[0], q[1]]

        new_prog = prog.compile(compiler=DummyCircuit())

        # check compiled program only has three gates
        assert len(new_prog) == 3

        # test gates are correct
        circuit = new_prog.circuit
        assert circuit[0].op.__class__.__name__ == "S2gate"
        assert circuit[1].op.__class__.__name__ == "Interferometer"
        assert circuit[2].op.__class__.__name__ == "MZgate"
    def test_mach_zehnder_interferometers(self, tol):
        """Test Mach-Zehnder gates correctly compile"""
        prog = sf.Program(4)
        phi = 0.543
        theta = -1.654

        with prog.context as q:
            ops.S2gate(0.5) | (q[0], q[2])
            ops.S2gate(0.5) | (q[3], q[1])
            ops.MZgate(phi, theta) | (q[0], q[1])
            ops.MZgate(phi, theta) | (q[2], q[3])
            ops.MeasureFock() | q

        res = prog.compile("chip0")

        expected = sf.Program(4)

        with expected.context as q:
            ops.S2gate(0.5, 0) | (q[0], q[2])
            ops.S2gate(0.5, 0) | (q[1], q[3])

            # corresponds to MZgate(phi, theta) on modes [0, 1]
            ops.Rgate(np.mod(phi, 2 * np.pi)) | q[0]
            ops.BSgate(np.pi / 4, np.pi / 2) | (q[0], q[1])
            ops.Rgate(np.mod(theta, 2 * np.pi)) | q[0]
            ops.BSgate(np.pi / 4, np.pi / 2) | (q[0], q[1])
            ops.Rgate(0) | q[0]
            ops.Rgate(0) | q[1]

            # corresponds to MZgate(phi, theta) on modes [2, 3]
            ops.Rgate(np.mod(phi, 2 * np.pi)) | q[2]
            ops.BSgate(np.pi / 4, np.pi / 2) | (q[2], q[3])
            ops.Rgate(np.mod(theta, 2 * np.pi)) | q[2]
            ops.BSgate(np.pi / 4, np.pi / 2) | (q[2], q[3])
            ops.Rgate(0) | q[2]
            ops.Rgate(0) | q[3]

            ops.MeasureFock() | (q[0], q[3], q[1], q[2])

        assert program_equivalence(res, expected, atol=tol)
    def test_no_unitary(self, tol):
        """Test compilation works with no unitary provided"""
        prog = sf.Program(8)

        with prog.context as q:
            ops.S2gate(SQ_AMPLITUDE) | (q[0], q[4])
            ops.S2gate(SQ_AMPLITUDE) | (q[1], q[5])
            ops.S2gate(SQ_AMPLITUDE) | (q[2], q[6])
            ops.S2gate(SQ_AMPLITUDE) | (q[3], q[7])
            ops.MeasureFock() | q

        res = prog.compile("Xunitary")
        expected = sf.Program(8)

        with expected.context as q:
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[0], q[4])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[1], q[5])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[2], q[6])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[3], q[7])

            # corresponds to an identity on modes [0, 1, 2, 3]
            # This can be easily seen from below by noting that:
            # MZ(pi, pi) = R(0) = I
            # MZ(pi, 0) @ MZ(pi, 0) = I
            # [R(pi) \otimes I] @ MZ(pi, 0) = I
            ops.MZgate(np.pi, 0) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.MZgate(np.pi, np.pi) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.Rgate(np.pi) | (q[0])
            ops.Rgate(0) | (q[1])
            ops.Rgate(0) | (q[2])
            ops.Rgate(0) | (q[3])

            # corresponds to an identity on modes [4, 5, 6, 7]
            ops.MZgate(np.pi, 0) | (q[4], q[5])
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, np.pi) | (q[5], q[6])
            ops.MZgate(np.pi, np.pi) | (q[4], q[5])
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, np.pi) | (q[5], q[6])
            ops.Rgate(np.pi) | (q[4])
            ops.Rgate(0) | (q[5])
            ops.Rgate(0) | (q[6])
            ops.Rgate(0) | (q[7])

            ops.MeasureFock() | q

        assert program_equivalence(res, expected, atol=tol, compare_params=False)

        # double check that the applied symplectic is correct

        # remove the Fock measurements
        res.circuit = res.circuit[:-1]

        # extract the Gaussian symplectic matrix
        O = res.compile("gaussian_unitary").circuit[0].op.p[0]

        # construct the expected symplectic matrix corresponding
        # to just the initial two mode squeeze gates
        S = two_mode_squeezing(SQ_AMPLITUDE, 0)
        num_modes = 8
        expected = np.identity(2 * num_modes)
        for i in range(num_modes // 2):
            expected = expand(S, [i, i + num_modes // 2], num_modes) @ expected
        # Note that the comparison has to be made at the level of covariance matrices
        # Not at the level of symplectic matrices
        assert np.allclose(O @ O.T, expected @ expected.T, atol=tol)
 def unitary(q):
     ops.MZgate(0.5, 0.1) | (q[0], q[1])
     ops.BSgate(0.1, 0.2) | (q[1], q[2])
     ops.Rgate(0.4) | q[0]
Esempio n. 11
0
    def test_no_unitary(self, chip, tol):
        """Test compilation works with no unitary provided"""
        prog = sf.Program(12)

        with prog.context as q:
            ops.S2gate(SQ_AMPLITUDE) | (q[0], q[6])
            ops.S2gate(SQ_AMPLITUDE) | (q[1], q[7])
            ops.S2gate(SQ_AMPLITUDE) | (q[2], q[8])
            ops.S2gate(SQ_AMPLITUDE) | (q[3], q[9])
            ops.S2gate(SQ_AMPLITUDE) | (q[4], q[10])
            ops.S2gate(SQ_AMPLITUDE) | (q[5], q[11])
            ops.MeasureFock() | q

        res = prog.compile(chip.short_name)
        expected = sf.Program(12)

        with expected.context as q:
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[0], q[6])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[1], q[7])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[2], q[8])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[3], q[9])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[4], q[10])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[5], q[11])

            # corresponds to an identity on modes [0, 1, 2, 3, 4, 5]
            # This can be easily seen from below by noting that:
            # MZ(pi, pi) = R(0) = I
            # MZ(pi, 0) @ MZ(pi, 0) = I
            # [R(pi) \otimes I] @ MZ(pi, 0) = I
            ops.MZgate(np.pi, 0) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, 0) | (q[4], q[5])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.MZgate(np.pi, np.pi) | (q[3], q[4])

            ops.MZgate(np.pi, 0) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, 0) | (q[4], q[5])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.MZgate(np.pi, np.pi) | (q[3], q[4])

            ops.MZgate(np.pi, 0) | (q[0], q[1])
            ops.MZgate(np.pi, np.pi) | (q[2], q[3])
            ops.MZgate(np.pi, np.pi) | (q[4], q[5])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.MZgate(np.pi, np.pi) | (q[3], q[4])

            ops.Rgate(np.pi) | (q[0])
            ops.Rgate(0) | (q[1])
            ops.Rgate(0) | (q[2])
            ops.Rgate(0) | (q[3])
            ops.Rgate(0) | (q[4])
            ops.Rgate(0) | (q[5])

            # corresponds to an identity on modes [6, 7, 8, 9, 10, 11]
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, 0) | (q[8], q[9])
            ops.MZgate(np.pi, 0) | (q[10], q[11])
            ops.MZgate(np.pi, np.pi) | (q[7], q[8])
            ops.MZgate(np.pi, np.pi) | (q[9], q[10])

            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, 0) | (q[8], q[9])
            ops.MZgate(np.pi, 0) | (q[10], q[11])
            ops.MZgate(np.pi, np.pi) | (q[7], q[8])
            ops.MZgate(np.pi, np.pi) | (q[9], q[10])

            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, np.pi) | (q[8], q[9])
            ops.MZgate(np.pi, np.pi) | (q[10], q[11])
            ops.MZgate(np.pi, np.pi) | (q[7], q[8])
            ops.MZgate(np.pi, np.pi) | (q[9], q[10])

            ops.Rgate(np.pi) | (q[6])
            ops.Rgate(0) | (q[7])
            ops.Rgate(0) | (q[8])
            ops.Rgate(0) | (q[9])
            ops.Rgate(0) | (q[10])
            ops.Rgate(0) | (q[11])

            ops.MeasureFock() | q

        # Check that the applied symplectic is correct

        # remove the Fock measurements
        res.circuit = res.circuit[:-1]

        # extract the Gaussian symplectic matrix
        O = res.compile("gaussian_unitary").circuit[0].op.p[0]

        # construct the expected symplectic matrix corresponding
        # to just the initial two mode squeeze gates
        S = TMS(SQ_AMPLITUDE, 0)

        expected = np.zeros([2*12, 2*12])
        l = 12 // 2
        ch = np.cosh(SQ_AMPLITUDE) * np.identity(l)
        sh = np.sinh(SQ_AMPLITUDE) * np.identity(l)
        zh = np.zeros([l, l])
        expected = np.block([[ch, sh, zh, zh], [sh, ch, zh, zh], [zh, zh, ch, -sh], [zh, zh, -sh, ch]])

        assert np.allclose(O, expected, atol=tol)
Esempio n. 12
0
    def test_no_unitary(self, tol):
        """Test compilation works with no unitary provided"""
        prog = sf.Program(8)

        with prog.context as q:
            ops.S2gate(SQ_AMPLITUDE) | (q[0], q[4])
            ops.S2gate(SQ_AMPLITUDE) | (q[1], q[5])
            ops.S2gate(SQ_AMPLITUDE) | (q[2], q[6])
            ops.S2gate(SQ_AMPLITUDE) | (q[3], q[7])
            ops.MeasureFock() | q

        res = prog.compile("X8_01")
        expected = sf.Program(8)

        with expected.context as q:
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[0], q[4])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[1], q[5])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[2], q[6])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[3], q[7])

            # corresponds to an identity on modes [0, 1, 2, 3]
            # This can be easily seen from below by noting that:
            # MZ(pi, pi) = R(0) = I
            # MZ(pi, 0) @ MZ(pi, 0) = I
            # [R(pi) \otimes I] @ MZ(pi, 0) = I
            ops.MZgate(np.pi, 0) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.MZgate(np.pi, 0) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.Rgate(0) | (q[0])
            ops.Rgate(0) | (q[1])
            ops.Rgate(0) | (q[2])
            ops.Rgate(0) | (q[3])

            # corresponds to an identity on modes [4, 5, 6, 7]
            ops.MZgate(np.pi, 0) | (q[4], q[5])
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, np.pi) | (q[5], q[6])
            ops.MZgate(np.pi, 0) | (q[4], q[5])
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, np.pi) | (q[5], q[6])
            ops.Rgate(0) | (q[4])
            ops.Rgate(0) | (q[5])
            ops.Rgate(0) | (q[6])
            ops.Rgate(0) | (q[7])

            ops.MeasureFock() | q

        assert program_equivalence(res, expected, atol=tol)

        # double check that the applied symplectic is correct

        # remove the Fock measurements
        res.circuit = res.circuit[:-1]

        # extract the Gaussian symplectic matrix
        O = res.compile("gaussian_unitary").circuit[0].op.p[0]

        # construct the expected symplectic matrix corresponding
        # to just the initial two mode squeeze gates
        S = TMS(SQ_AMPLITUDE, 0)

        expected = np.zeros([2 * 8, 2 * 8])
        idx = np.arange(2 * 8).reshape(4, 4).T
        for i in idx:
            expected[i.reshape(-1, 1), i.reshape(1, -1)] = S

        assert np.allclose(O, expected, atol=tol)