【问题标题】:How to write C# implementation for a Q# operation with intrinsic body?如何为具有内在主体的 Q# 操作编写 C# 实现?
【发布时间】:2019-11-10 01:01:04
【问题描述】:

我在 C# 中创建了一个用于 Q# 程序的库。该库有两个脚本,一个名为“Class1.cs”的 C# 类库和一个名为“Util.qs”的匹配 Q# 脚本,我在这里分享每个的代码 sn-p:

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; }
}

在不同的命名空间中有另一个 Q# 程序使用命名空间“MyLibrary”,所以在添加引用后,在这个 Q# 程序中我有:

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

    open MyLibrary;

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

当我在终端中执行“dotnet run”时,我会收到以下消息:

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.

我该如何解决?

谢谢。

更新:

按照 Mariia 的回答并检查 Quantum.Kata.Utils,我将代码更改如下:

所以,我将 Class1 脚本更改为:

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;
            };
        }
}

现在错误消息是:

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

检查 Quantum.Kata.Utils 后,我意识到我需要为作为基类的 Class1 创建一个字段和一个构造函数,并且我应该覆盖 Func&lt;string, QVoid&gt;,因为 Op_1 参数是字符串类型。但我不确定这些步骤中的每一个是否单独完成?

第二次更新:

我在第一次更新时将之前的 c# 代码更改为以下代码:

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;
            };
        }
}

现在错误信息与第一条相同:

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.

在这个新代码中,构造函数public Class1() { } 不应该有参数吗?如果是,是什么数据类型?

【问题讨论】:

    标签: q#


    【解决方案1】:

    在您的代码中,没有任何东西将 Q# 操作 Op_1 和您打算在 Method_1 中实现它的 C# 代码联系起来。

    Q# 操作被编译成类。要为带有内部主体的 Q# 操作定义 C# 实现,您必须定义一个实现 Q# 操作编译成的抽象类的类;所以你会有类似public class Op_1_Impl : Op_1的东西。

    正确处理所有管道可能有点棘手(毕竟这是一个 hack!)我建议查看操作 GetOracleCallsCountits C# implementation 以查看必须到位的确切部件工作。


    对于更新后的问题,您的方法的签名表明它将字符串作为输入并且不返回任何内容 (QVoid),但实现会尝试返回字符串 cl_1,因此您会得到 Cannot implicitly convert type 'string' to 'Microsoft.Quantum.Simulation.Core.QVoid'

    【讨论】:

    • 感谢 Mariia 的回答,我尝试调整我的代码但没有通过,所以我更新了我的问题,请您再检查一遍,谢谢。
    • 更新了答案。我没有尝试在本地运行您的代码,但错误消息似乎很简单。
    • 我之前尝试过return QVoid.Instance,但再次收到此错误消息:Unhandled Exception: System.AggregateException: One or more errors occurred. (Cannot create an instance of MyLibrary.Op_1 because it is an abstract class.) ---&gt; System.MemberAccessException: Cannot create an instance of MyLibrary.Op_1 because it is an abstract class.
    • 我还添加了第二个更新,除了更改返回类型外,还对代码进行了一些更改。请参阅第二次更新。
    【解决方案2】:

    要为您的 Op_1 Q# 操作提供自定义 C# 仿真,您需要将 Class1.cs 替换为以下内容:

    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;
                };
            }
        }
    }
    

    然后您可以使用 QuantumSimulator 运行 Test1Library

    话虽如此,正如 Mariia 所说,这是一种 hacky、未记录的功能,将来可能会发生变化,请问您为什么需要这个?

    【讨论】:

    • 感谢您的回答。我需要创建一个可以处理某些字符串的操作。由于 Q# 中的字符串只是为了向用户显示消息,所以我打算创建一个操作来操作字符串。实际上这是我为什么这样做的一个很长的解释......我在我的代码中使用了你的答案但收到了这条消息:no suitable method found to override
    • 我确定代码有效,但您需要 1. 使用最新版本的 QDK (0.10.1911.1607); 2.确保Body定义中的输入参数类型匹配; 3. 确保操作的名称和命名空间匹配。如果你把你的样本放在一个要点中,我可以快速浏览一下。
    猜你喜欢
    • 2011-04-15
    • 2022-09-27
    • 2017-02-20
    • 1970-01-01
    • 2010-10-04
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多