How to write C# implementation for a Q# operation with intrinsic body?

守給你的承諾、 提交于 2020-01-06 08:13:00

问题


I have created a library in C# to be used in Q# programs. The library has two scripts, a C# class library called "Class1.cs" and a matching Q# script called "Util.qs", I share the code snippet of each here:

Class1.cs:

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

namespace MyLibrary {
    class Class1 : QuantumSimulator {

        static void Method_1 (string str) { ... }
        .
        .
        .
    }
}

Util.qs:

namespace MyLibrary {
    operation Op_1 (str : String)  : Unit { body intrinsic; }
}

There is another Q# program in a different namespace that uses the namespace "MyLibrary" so after adding reference, in this Q# program I have:

namespace QSharp
{
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;

    open MyLibrary;

    operation TestMyLibrary() : Unit {
        Op_1("some string");
    }
}

When I execute "dotnet run" in the terminal I receive this message:

Unhandled Exception: System.AggregateException: One or more errors
occurred. (Cannot create an instance of MyLibrary.Op_1 because it is
an abstract class.) ---> System.MemberAccessException: Cannot create
an instance of MyLibrary.Op_1 because it is an abstract class.

How can I fix it?

Thanks.

UPDATE:

Following Mariia' answer and also checking Quantum.Kata.Utils, I changed my code as following:

So, I changed Class1 script to:

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

namespace MyLibrary {
    class Class1 : QuantumSimulator {

        private string classString = "";

        public Class1() { }

        public class Op_1_Impl : Op_1{

            string cl_1;

            public Op_1_Impl (Class1 c) : base (c) {
                cl_1 = c.classString;
            }

            public override Func<string, QVoid> Body => (__in) => {
               return cl1;
            };
        }
}

Now the error messages are:

error CS0029: Cannot implicitly convert type 'string' to 'Microsoft.Quantum.Simulation.Core.QVoid' 
error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types
in the block are not implicitly convertible to the delegate return type

Having checked Quantum.Kata.Utils, I realised I need to create a field and a constructor for Class1 which is a base class and also I should override Func<string, QVoid> as the Op_1 parameter is string type. But I am not sure if each of these steps individually is done properly?

Second Update:

I have changed the previous c# code in first update to the following one:

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

namespace MyLibrary {
    class Class1 : QuantumSimulator {

        public Class1() { }

        public class Op_1_Impl : Op_1{

            Class1 cl_1;

            public Op_1_Impl (Class1 c) : base (c) {
                cl_1 = c;
            }

            public override Func<string, QVoid> Body => (__in) => {
               return QVoid.Instance;
            };
        }
}

Now the error message is the same as the very first one:

Unhandled Exception: System.AggregateException: One or more errors
occurred. (Cannot create an instance of MyLibrary.Op_1 because it is
an abstract class.) ---> System.MemberAccessException: Cannot create
an instance of MyLibrary.Op_1 because it is an abstract class.

And also in this new code shouldn't the constructor public Class1() { } have a parameter? if so what datatype?


回答1:


In your code, there is nothing connecting the Q# operation Op_1 and the C# code that you intend to implement it in Method_1.

Q# operations are compiled into classes. To define a C# implementation for a Q# operation with the intrinsic body, you have to define a class that implements the abstract class into which your Q# operation gets compiled; so you would have something like public class Op_1_Impl : Op_1.

Getting all the piping right can be a bit tricky (it's a hack, after all!) I would recommend looking at the operation GetOracleCallsCount and its C# implementation to see the exact pieces that have to be in place for it to work.


For the updated question, the signature of your method says that it takes string as an input and returns nothing (QVoid), but the implementation tries to return a string cl_1, so you get a Cannot implicitly convert type 'string' to 'Microsoft.Quantum.Simulation.Core.QVoid'.




回答2:


To provide a custom C# emulation for your Op_1 Q# operation, you'll need to replace your Class1.cs with something like this:

using System;
using Microsoft.Quantum.Simulation.Core;


namespace MyLibrary
{
    public partial class Op_1
    {
        public class Native : Op_1
        {
            public Native(IOperationFactory m) : base(m) { }
            public override Func<String, QVoid> Body => (str) =>
            {
                // put your implementation here.
                Console.WriteLine(str);
                return QVoid.Instance;
            };
        }
    }
}

You can then run the Test1Library using the QuantumSimulator.

That being said, as Mariia said, this is kind of hacky, undocumented functionality that might change in the future, may I ask why you need this?



来源:https://stackoverflow.com/questions/58784924/how-to-write-c-sharp-implementation-for-a-q-operation-with-intrinsic-body

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!