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?).
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.
User contributions licensed under CC BY-SA 3.0