How do I properly manage the lifetime of a Qubit in C#

3

I'm playing around with Q#, which uses C# as a driver. I'd like to pass a Qubit object to the Q# code but it isn't working as expected.

C# Driver

using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Simulators;

namespace Quantum.QSharpApplication1 {
    class Driver {
        static void Main(string[] args) {
            using (var sim = new QuantumSimulator()) {
                var x = new Microsoft.Quantum.Simulation.Common.QubitManager(10);
                Qubit q1 = x.Allocate();
                Solve.Run(sim, q1, 1);
                }
            System.Console.WriteLine("Press any key to continue...");
            System.Console.ReadKey();
            }
        }
    }

Q#

namespace Quantum.QSharpApplication1
{
    open Microsoft.Quantum.Primitive;
    open Microsoft.Quantum.Canon;

    operation Solve (q : Qubit, sign : Int) : ()
    {
        body
        {
            let qp = M(q);
            if (qp != Zero)
            {
                X(q);
            }     
            H(q);
        }
    }
}

When I run this, it runs without error until it reaches the System.Console.* lines at which point it throws the following exception in the Q# code

System.AccessViolationException
  HResult=0x80004003
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=<Cannot evaluate the exception source>
  StackTrace:
<Cannot evaluate the exception stack trace>

The debugger associates this with the "let qp = M(q);" line in Q#.

Note this does happen in the Solve.Run call, the real code has multiple Solve calls and the output appear correct. It only appears to occur after the using QuantumSimulator scope is left. I recall reading that the Qubit must be reset to zero before it is released. I'm not sure if that is the problem here, but I don't see a way to do that in C#. Interesting I remove the Console lines, the program will run without error (timing?).

c#
q#
asked on Stack Overflow Jun 30, 2018 by Dweeberly • edited Feb 15, 2021 by Shog9

1 Answer

3

The QubitManager instance you used to create the qubits is not a singleton (each Simulator has its own QubitManager), therefore the Simulator is not aware of the Qubit your trying to manipulate on the Q# code, thus the AccessViolationException.

In general, creating Qubits on the driver is not supported; you can only allocate qubits using the allocate and borrowing statements inside Q#. The recommendation is to create an entry point in Q# to allocate the qubits which does the qubit allocation and call this from the driver, for example:

// MyOp.qs
operation EntryPoint() : () 
{
    body
    {
        using (register = Qubit[2]) 
        {
            myOp(register);
        }
    }
}


// Driver.cs
EntryPoint.Run().Wait();

Finally, note that in your driver code you have this: Solve.Run(sim, q1, 1);

The Run method returns a tasks that executes asynchronously. You must typically add a Wait() to make sure it finishes execution: EntryPoint.Run(sim, 1).Wait();

If you do this you will notice that failure during the Run, not the Console.WriteLine.

answered on Stack Overflow Jul 2, 2018 by El capi

User contributions licensed under CC BY-SA 3.0