将复杂对象传递给 Q# 操作

Passing complex objects to Q# operations

我想将复杂对象从 Python 代码传递给 Q# 操作。我在两侧定义了相同的数据结构:在 Python 中作为 class 并且在 Q# 中作为 newtype . 比我在复杂对象的 Python 中准备了一个 JSON 表示(利用 json 包和 this answer)并试图通过它到 Q# 操作,但出现以下错误:

Received invalid parameters. Please fix and try again:
n: Unexpected initial token 'String' when populating object. Expected JSON object or array. Path '', line 1, position 171.

这是Python代码

import qsharp
import json
import inspect

from json.test import JsonTest

class ObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "to_json"):
            return self.default(obj.to_json())
        elif hasattr(obj, "__dict__"):
            d = dict(
                (key, value)
                for key, value in inspect.getmembers(obj)
                if not key.startswith("__")
                and not inspect.isabstract(value)
                and not inspect.isbuiltin(value)
                and not inspect.isfunction(value)
                and not inspect.isgenerator(value)
                and not inspect.isgeneratorfunction(value)
                and not inspect.ismethod(value)
                and not inspect.ismethoddescriptor(value)
                and not inspect.isroutine(value)
            )
            return self.default(d)
        return obj

class U:
    x = 0
    y = 0
    z = 0
    def __init__(self, x, y, z) :
        self.x = x
        self.y = y
        self.z = z

class N:
    t = [U(0,0,0), U(3.14,0,0)]
    q = 3
    def __init__(self, t, q) :
        self.t = t
        self.q = q

obj = N([U(3.14, 0, 0), U(0, 3.14, 0)], 3)
jsonObj = json.dumps(obj, cls=ObjectEncoder, indent=2, sort_keys=False)
print(jsonObj)
JsonTest.simulate(n=jsonObj)

这是 JSON 由该代码打印的演示文稿

{
  "q": 3,
  "t": [
    {
      "x": 3.14,
      "y": 0,
      "z": 0
    },
    {
      "x": 0,
      "y": 3.14,
      "z": 0
    }
  ]
}

这是Q#代码

namespace json.test {

    open Microsoft.Quantum.Convert;
    open Microsoft.Quantum.Intrinsic;

    newtype U = (
        x : Double,
        y : Double,
        z : Double  
    );

    newtype N = (
        t : U[],
        q : Int
    );

    operation JsonTest(n : N) : Int {
        let r = n::q * Length(n::t); // just do sometinhg
        Message($"t = {n::t}  q = {n::q}");
        return r;
    }
}

Q# 实际上支持 JSON 复杂对象的表示吗?

是的,Q# 支持通过 Python 表示这些用户定义类型的实例,但不使用 dict 或 JSON 字符串。要使用 Q# 界面,我们需要改用 tuples。如果你想要一个包含你正在使用的标签的数据结构(xyz 等等),我建议使用 namedtuples,例如:

from collections import namedtuple

U = namedtuple("U", ["x", "y", "z"])
N = namedtuple("N", ["t", "q"])

obj = N(q=3, t=[U(x=3.14, y=0, z=0), U(x=0, y=3.14, z=0)])

这样

>>> obj
N(t=[U(x=3.14, y=0, z=0), U(x=0, y=3.14, z=0)], q=3)

然后您可以像这样简单地将其传递给编译的 Q# 程序:

import qsharp

qsharp.compile("""
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Intrinsic;

newtype U = (
    x: Double, 
    y: Double, 
    z: Double
);

newtype N = (
    t: U[],
    q: Int
);
""")

JsonTest = qsharp.compile("""
operation JsonTest(n : N) : Int {
    let r = n::q * Length(n::t); // just do sometinhg
    Message($"t = {n::t}  q = {n::q}");
    return r;
}
""")

from collections import namedtuple

U = namedtuple("U", ["x", "y", "z"])
N = namedtuple("N", ["t", "q"])

obj = N(q=3, t=[U(x=3.14, y=0, z=0), U(x=0, y=3.14, z=0)])
JsonTest.simulate(n=obj)

哪个returns

t = [U((3.14, 0, 0)),U((0, 3.14, 0))]  q = 3
6

如果你想使用 JSON 个字符串,你可以像这样创建一个自定义函数:

import json

def N_from_json(data: str):
    """Create N object from JSON-formatted string
    """
    _data = json.loads(data)
    t = _data.get("t", [])
    q = _data.get("q", 0) # Or some other default value of your choosing

    return N(t=[U(**_t) for _t in t], q=q)


jsonObj = json.dumps({
  "t": [
    {
      "x": 3.14,
      "y": 0,
      "z": 0
    },
    {
      "x": 0,
      "y": 3.14,
      "z": 0
    }
  ],
  "q": 3,
})

obj = N_from_json(jsonObj)