量子编程初步——Q#入门

1 安装

Q#@VSCODE

目前,微软提供的QDK既可以作为一门独立语言运行,也可以嵌入Python或C#、F#等.NET语言进行工作。但无论在哪里工作,都必须安装.Net Core3.1

如果使用VS Code,则在插件栏中搜索Microsoft Quantum Development Kit Preview,点击安装,下载Q#可能需要一点时间。

安装成功后,可以创建新项目:快捷键Ctrl+Shift+P,输入“Q#:Create New Project->选择Standalone console application->在弹出的对话框中输入项目名称test,然后创建。

在创建的test文件夹中有一个Program.qs文件,在终端中进入test文件夹,然后输入dotnet run,就可以运行这个Q#程序

PS E:\Code\test> dotnet run
Hello quantum world!

Q# @ Python

若希望通过Python运行Q#,最便捷的方式是通过conda进行。

conda create -n qsharp -c microsoft qsharp notebook
conda activate qsharp
python -c "import qsharp"

create -n用于创建环境,activate用于激活环境,conda会自动下载需要的内容,进入环境之后,写一个示例程序Operation.qs

namespace Qrng {
    open Microsoft.Quantum.Intrinsic;

    operation qGenerator() : Result {
        use q = Qubit(); // 设置一个Q比特
        H(q);            
        let r = M(q);    // 测量Q比特的值
        Reset(q);
        return r;
    }
}

在相同的文件夹下进入python,调用该文件

python
>>>import qsharp
>>>from Qrng import qGenerator()
>>> print(qGenerator.simulate())
0
>>> print(qGenerator.simulate())
0
>>> print(qGenerator.simulate())
1

Q# @ dotnet

首先下载Qsharp的模板,然后通过dotnet命令创建新的Q#程序。

>dotnet new -i Microsoft.Quantum.ProjectTemplates
>dotnet new console -lang Q# -o runSayHello
>cd runsayHello
>dotnet run
Hello quantum world!

如果希望在C#等程序中调用Q#,则需要创建Q#库

>dotnet new classlib -lang Q# -o quantum
>dotnet new console -lang C# -o host
>cd host
>dotnet add refrence ../quantum/quantum.csproj
已将引用“..\quantum\quantum.csproj”添加到项目。

2 创建贝尔态

在命令行中输入

$ dotnet new console -lang Q# --output Bell
$ cd Bell 
$ code .

其中,-lang Q#表示选择基于Q#语言的模板,code.表示使用vscode进行编辑。我们主要编辑的是Bell文件夹下的Program.qs。

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

    //翻转量子比特
    operation Set(Desired:Result, q1:Qubit):Unit{
        if(Desired != M(q1)){
            X(q1);
        }
    }

    @EntryPoint()       //入口标志
    operation Test():Unit{
        mutable numOnes = 0;
        let count = 1000;
        let initial = One;
        use q = Qubit(){
            for _ in 1..count {
                Set(initial, q);
                let res = M(q);
                if(res==One){
                    set numOnes += 1;
                }}
            Set(Zero, q);}
        Message($"num of 0s: {count-numOnes}, num of 1s: {numOnes}");
    }
}

该程序可在命令行调用:

.\Bell>dotnet run
num of 0s: 0, num of 1s: 1000

也可在python中调用:

>>> import qsharp
Preparing Q# environment...
>>> from Bell import Test
>>> Test.simulate()
num of 0s: 0, num of 1s: 1000
()
>>>

入口函数当然可以拥有输入输出,且非常方便命令行的调用,例如下面的量子纠缠程序

namespace Bell {
    open Microsoft.Quantum.Canon;
    open Microsoft.Quantum.Intrinsic;
    
    operation Set(Desired:Result, q1:Qubit):Unit{
        if(Desired != M(q1)){
            X(q1);  //X 表示Pauli矩阵X
        }
    }

    @EntryPoint()
    operation TestBellState(count : Int, initial : Result) : (Int, Int, Int) {
        mutable numOnes = 0;
        mutable agree = 0;
        use (q0, q1) = (Qubit(), Qubit());
        for test in 1..count {
            Set(initial, q0);
            Set(Zero, q1);

            H(q0);
            CNOT(q0, q1);
            let res = M(q0);

            if M(q1) == res {
                set agree += 1;
            }

            if res == One {
                set numOnes += 1;
            }
        }

        Set(Zero, q0);
        Set(Zero, q1);
        
        Message("Test results (# of 0s, # of 1s, # of agreements)");
        return (count-numOnes, numOnes, agree);
    }
}

则在命令行中调用

>dotnet run --count 1000 --initial One
>(505, 495, 1000)

3 量子计算基础

量子比特

在Q#语言中,Qubit代表一个量子比特,尽管看上去只有Zero和One两种取值,但并非Bool型。之所以呈现出这两种取值,关键在于我们采取了测量操作,而在测量之前,量子比特实际上处于 ∣ 0 ⟩ |0\rangle 0 ∣ 1 ⟩ |1\rangle 1的一种叠加状态。

在量子力学中,态矢等同于波函数,波函数则是Hilbert空间中的某一组正交基的线性组合,所以并不能等同于宏观世界的常量,亦即不遵守 ∣ 0 ⟩ + ∣ 1 ⟩ = ∣ 1 ⟩ |0\rangle+|1\rangle=|1\rangle 0+1=1的运算方式。

所以,Zero和One也不能单纯地理解为 ∣ 0 ⟩ |0\rangle 0 ∣ 1 ⟩ |1\rangle 1,而是需要在态叠加的基础上去理解,作为 ∣ 0 ⟩ |0\rangle 0 ∣ 1 ⟩ |1\rangle 1的某种线性组合,即

One = [ 1 0 ] , Zero = [ 0 1 ] \text{One}=\begin{bmatrix}1 \\ 0\end{bmatrix},\text{Zero}=\begin{bmatrix}0 \\ 1\end{bmatrix} One=[10],Zero=[01]

而qubit的状态,便由One和Zero的线性组合组成,由于Hilbert空间连续,所以qubit的取值无穷多。但这并不意味着qubit和二维复空间一一对应,只有 L 2 L_2 L2范数为1的向量才能描述qubit的状态,即对于某一qubit,对于量子态 α ∣ 0 ⟩ + β ∣ 1 ⟩ \alpha|0\rangle+\beta|1\rangle α0+β1,有 α 2 + β 2 = 1 \alpha^2+\beta^2=1 α2+β2=1

对于观测操作M()之前的qubit,可能处于任何一种叠加状态,由于测量导致波包塌缩,从而被观测到确定的值。这就是广为流传到薛定谔的猫,当我们观测之前,猫处于一种死和活的叠加态。

量子门

谈及量子门之前,有必要回顾一下人所共知的逻辑门,其操作单元为bool型变量,其物理实现为门电路。

在python语言中,通过and,or,not实现与或非的二元运算。这种二元运算满足对bool这种数据类型的封闭性——这也是量子门的运算所需要遵循的。

单个qubit的态矢量为 L 2 L_2 L2范数为1的二维列向量,从属于在二次酉群。所以量子门的作为矩阵形式存在时,其行列式d的绝对值为1。此外,量子门的物理意义是表示力学量的算符,由于量子力学要求算符具备幺正性质,所以其矩阵表达亦必为幺正矩阵,即其共轭转置矩阵与其逆矩阵相等。对于矩阵 S S S,其共轭转置矩阵表示为 S † S ^{\dagger} S,则有 S S † = I SS ^{\dagger} = I SS=I

可见,单位矩阵天然满足这一要求,除此之外,通过求解狄拉克方程,可以得到基于Pauli矩阵的波函数表达形式,泡利矩阵显然可以作为量子门,其表达式为

P x = [ 0 1 1 0 ] , P y = [ 0 − i i 0 ] , P z = [ 1 0 0 − 1 ] P_x=\begin{bmatrix}0&1\\1&0\end{bmatrix},P_y=\begin{bmatrix}0&-i\\i&0\end{bmatrix},P_z=\begin{bmatrix}1&0\\0&-1\end{bmatrix} Px=[0110],Py=[0ii0],Pz=[1001]

可以证明,任意幺正矩阵均可分解成Pauli矩阵的形式:

U = e i α R z ( β ) R y ( γ ) R x ( δ ) U = e^{i\alpha}R_z(\beta)R_y(\gamma )R_x(\delta ) U=eiαRz(β)Ry(γ)Rx(δ)

其中,

R z ( β ) = e − i β Z / 2 = c o s β 2 I − i s i n β 2 Z = ∣ e − i β / 2 0 0 e i β / 2 2 ∣ R_z(\beta) = e^{-i\beta Z/2} = cos \frac{\beta}{2}I - isin{\frac {\beta}{2}}Z = \begin{vmatrix}e^{-i\beta/2} & 0 \\ 0 & e^{i\beta/2} {2}\end{vmatrix} Rz(β)=eiβZ/2=cos2βIisin2βZ=eiβ/200eiβ/22

R y ( γ ) = e − i γ Y / 2 = c o s γ 2 I − i s i n γ 2 Y = ∣ c o s γ 2 − s i n γ 2 s i n γ 2 c o s γ 2 ∣ R_y(\gamma) = e^{-i\gamma Y/2} = cos \frac{\gamma}{2}I - isin{\frac {\gamma}{2}}Y = \begin{vmatrix}cos \frac{\gamma}{2} & -sin \frac{\gamma}{2}\\ sin \frac{\gamma}{2} & cos \frac{\gamma}{2}\end{vmatrix} Ry(γ)=eiγY/2=cos2γIisin2γY=cos2γsin2γsin2γcos2γ

R x ( δ ) = e − i δ X / 2 = c o s δ 2 I − i s i n δ 2 X = ∣ c o s δ 2 − i s i n δ 2 − i s i n δ 2 c o s δ 2 ∣ R_x(\delta) = e^{-i\delta X/2} = cos \frac{\delta}{2}I - isin{\frac {\delta}{2}}X = \begin{vmatrix}cos \frac{\delta}{2} & -i sin \frac{\delta}{2} \\ -isin \frac{\delta}{2} & cos \frac{\delta}{2}\end{vmatrix} Rx(δ)=eiδX/2=cos2δIisin2δX=cos2δisin2δisin2δcos2δ

正如量子比特与二维单位向量之间存在一一对应关系,量子门与幺正矩阵之间也存在一一对应关系。除了Pauli矩阵之外,还有一些常用的量子门

H a d a m a r d = 1 2 [ 1 1 1 − 1 ] , P h a s e = [ 1 0 0 i ] , π / 8 = [ 1 0 0 e i π / 4 ] Hadamard=\frac{1}{\sqrt{2}}\begin{bmatrix}1&1\\1&-1\end{bmatrix},Phase=\begin{bmatrix}1&0\\0&i\end{bmatrix}, \pi/8=\begin{bmatrix}1&0\\0&e^{i\pi/4}\end{bmatrix} Hadamard=2 1[1111],Phase=[100i],π/8=[100eiπ/4]

在示例程序中所用到的HM便都是量子门,在Q#标准库中封装了许多量子门,列如下:

名称签名式量子门矩阵
X(Qubit => () : Adjoint, Controlled) [ 0 1 1 0 ] \begin{bmatrix}0&1\\1&0\end{bmatrix} [0110]
Y(Qubit => () : Adjoint, Controlled) [ 0 − i i 0 ] \begin{bmatrix} 0&-i \\ i&0 \end{bmatrix} [0ii0]
Z(Qubit => () : Adjoint, Controlled) [ 1 0 0 − 1 ] \begin{bmatrix} 1&0 \\ 0&-1 \end{bmatrix} [1001]
H(Qubit => () : Adjoint, Controlled) 1 2 [ 1 1 1 − 1 ] \frac {1} {\sqrt{2}} \begin{bmatrix} 1&1\\1&-1\end{bmatrix} 2 1[1111]
S(Qubit => () : Adjoint, Controlled) [ 1 0 0 i ] \begin{bmatrix} 1 \quad 0 \\ 0 \quad i \end{bmatrix} [100i]
T(Qubit => () : Adjoint, Controlled) [ 1 0 0 e i π / 4 ] \begin{bmatrix} 1 \qquad 0 \\ 0 \quad e^{i \pi / 4} \end{bmatrix} [100eiπ/4]
CNOT((Qubit, Qubit) => () : Adjoint, Controlled) [ 1 0 0 0 0 1 0 0 0 0 1 1 0 1 0 ] \begin{bmatrix}1&0&0&0\\0&1&0&\\0&0&0&1\\1&0 &1&0\end{bmatrix} 100101000001010
SWAP((Qubit, Qubit) => () : Adjoint, Controlled) [ 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 ] \begin{bmatrix}1 & 0 & 0 & 0 \\0 & 0 & 1 & 0 \\0 & 1 & 0 & 0 \\0 & 0 & 0 & 1\end{bmatrix} 1000001001000001

此外,由于量子态只有在被观测之后才有意义,所以Q#理所当然地提供了测量算符M,

Dirac符号

量子论因Schrodinger方程而升级为量子力学,波动力学创建不久,海森堡等人便提出了量子力学的矩阵形式。两者殊途同归于Hilbert空间之中。Dirac符号充分利用了Hilbert空间的优良性质,并通过左矢(bra)右矢(ket)完美指代算符与共轭算符、行向量和列向量的变化关系。

∣ 0 ⟩ |0\rangle 0 ∣ 1 ⟩ |1\rangle 1便是Dirac符号表述下的波函数,二者皆为右矢,可以理解为列向量。 ⟨ 0 ∣ \langle0| 0 ⟨ 1 ∣ \langle1| 1则为左矢,可以理解为行向量。

运算对应的矩阵运算
Z ∗ Z ^* Z复数 Z Z Z的共轭, ( 1 + i ) ∗ = ( 1 − i ) (1 + i) ^* = (1 - i) (1+i)=(1i)
⟨ φ ∥ ψ ⟩ \langle \varphi \| \psi \rangle φψ矢量内积
∥ φ ⟩ ⟨ ψ ∥ \| \varphi \rangle \langle \psi \| φψ矢量外积
∥ φ ⟩ ⨂ ∥ ψ ⟩ \| \varphi \rangle \bigotimes \| \psi \rangle φψ张量积, ⨂ \bigotimes 可省略
A ∗ A ^* A矩阵的共轭
A T A ^{T} AT矩阵转置
A † A ^{\dagger} A矩阵 A A A 的转置共轭, [ a b c d ] † = [ a ∗ c ∗ b ∗ d ∗ ] \begin{bmatrix} a&b\\c&d\end{bmatrix} ^\dagger = \begin{bmatrix} a^*&c^* \\b^*&d^*\end{bmatrix} [acbd]=[abcd]
⟨ φ ∥ A ∥ ψ ⟩ \langle\varphi\|A\|\psi\rangle φAψ ∥ φ ⟩ \|\varphi\rangle φ A ∥ ψ ⟩ A\|\psi\rangle Aψ 的内积,等价于 A † ∥ φ ⟩ A^{\dagger} \| \varphi \rangle Aφ ∥ ψ ⟩ \| \psi \rangle ψ 的内积

其中,张量积 ⨂ \bigotimes

∣ α ⟩ ⨂ ∣ β ⟩ = [ α 1 ∣ β ⟩ α 2 ∣ β ⟩ ⋮ α N ∣ β ⟩ ] | \alpha \rangle \bigotimes | \beta \rangle = \begin{bmatrix} \alpha_{1} |\beta \rangle \\ \alpha_{2} |\beta \rangle \\ \vdots \\ \alpha_{N}|\beta \rangle \end{bmatrix} αβ=α1βα2βαNβ

4 语言特性

数据类型

Q#提供了一些基础数据类型,包括IntDoubleBoolString等,其初始值分别为0,False或空。BigInt为任意大的数,基于.NET BigInteger类型。

Q#还提供了序列(Range)、元组(Tuple)、数组(Array)和自定义数据类型,其使用方法如下:

let T = (T0, T1, ..., Tn)	//	()表示元组,T0,T1可为不同类型
let (a,(b,c)) = (1,(2,3));  //	元组不支持下标索引,通过解构的方式赋值变量a = 1;b = 2;c = 3
let zeros = new Int[13];	//	数组用方括号表示,可用new定义,其数据类型可以为元组,默认初始化为0
let arr = [1; 2; 3; 4];		//	数组也可不用new直接定义
let arr = arr[1..2..4]; 	//	数组支持下标索引,且支持范围表达式,arr = [2; 4]
newtype TypeName = (T1,T2,...);	//新定义数据类型,T1、T2可以是任意数据类型

Q#中的变量通过let进行声明,编译器会自动根据其值判断数据类型。然而变量一经let,就是不可变的量了。即下列代码中的第三行会报错。

为了使变量变得名副其实,需要使用关键字mutable对其进行声明。

let a = 1; 			// a的类型为Int
let b = (1,2); 		//b的类型为(Int,Int)
a = 2;				//错误的表达式
let a = 2;			//错误的表达式
mutable c = 1;
d = 2;				//正确的表达式

特殊数据类型

除了以上这些常见的数据类型之外,Q#还提供了用于量子计算的数据类型

Qubit为qubit,只能通过使用operation对其进行各种操作。
Q#中,qubit没有对应的字面量,将qubit或qubit数组绑定到一个符号上构成一个量子位表达式(Qubit expressions)。
PauliPauli门,包括:PauliXPauliYPauliZPauliI
上述四个值都是合法的泡利表达式,将这些值或这些值组成的数组绑定至一个符号上也构成合法的泡利表达式。
Result表示测量结果,为枚举类型,包括OneZero,代表 ∥ 1 ⟩ \|1 \rangle 1 ∥ 0 ⟩ \|0\rangle 0
除此二者,还可将它们组成的数组绑定至一个符号。需要注意,One并不等于整数1,两者之间不可直接转换,但是Zero与0是相等的。
operation可调用类型,用来定义和执行量子操作,相当于量子函数
function可调用类型,与operation类似,相当于普通函数,不能进行量子操作

控制结构与操作符

Q#中的运算符并没有太多的花样

操作符简介
-,~~~,!负数,按位取反,逻辑非
-,/,*,^,%减法,除法,乘法,乘方,取模
+加,数组相加,字符串相加
<<<,>>>算数右移,算数左移
<,<=,>,>=小于,小于等于,大于,大于等于
==,!=相等,不等
&&&,^^^ ,\|\|\|按位与, 按位异或,按位或
&&,\|\|逻辑与,逻辑或

Q#提供了常见的if-else和for语句,使用方法如下

//0 .. n-2为范围表达式(Range expressions),表示0,1,2...n-2
for (index in 0 .. n-2) {
    set results[index] = Measure([PauliX], [qubits[index]]);
}

if (i == 1) {
    X(target);
} elif (i == 2) {
    Y(target);
} else {
    Z(target);
}

此外,Q#还提供了Repeat-Until-Success循环,repeat语句支持量子计算中的“repeat until success”模型,包括repeatuntilfixup关键字,repeat为循环体,until为循环条件。

repeat语句的执行过程为:首先执行循环体,然后测试条件表达式是否为true,如果为true,则语句结束,如果为false,则执行fixup语句中的内容,然后重新开始repeat语句的执行。需要注意的是,fixup不可省略,如果fixup代码块不做任何工作,只需写一个空的表达式()即可。

下面的代码展示了repeat语句的使用,该代码定义了量子门 V 3 = I + 2 i Z 5 V_3=\frac{I+2iZ}{\sqrt{5}} V3=5 I+2iZ

using ancilla = Qubit[1] {
    repeat {
        let anc = ancilla[0];
        H(anc);
        T(anc);
        CNOT(target,anc);
        H(anc);
        (Adjoint T)(anc);
        H(anc);
        T(anc);
        H(anc);
        CNOT(target,anc);
        T(anc);
        Z(target);
        H(anc);
        let result = M([anc],[PauliZ]);
    } until result == Zero
    fixup {
        ();//空语句
    }
}
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
很抱歉,根据提供的引用内容,我无法直接回答您关于量子计算机编程的PDF的问题。引用提到了量子编程语言,但并没有提及PDF文件。另外,引用和提到了量子计算机的关键词和体系结构,但同样没有提及PDF文件。 然而,我可以为您提供一些关于量子计算机编程的一般信息,希望对您有所帮助。 量子计算机编程是指使用特定的编程语言和算法来设计和实现在量子计算机上运行的程序。与传统的计算机编程不同,量子计算机编程涉及到利用量子比特(qubit)的特性进行计算。 目前,已经存在一些量子编程语言,例如Qiskit、Q#和Cirq等。这些语言提供了一系列的量子算法和工具,使得开发人员能够利用量子计算机的优势来解决特定的问题。 此外,了解量子计算机的物理实现也是量子计算机编程的重要一步。引用和提到了物理实现的内容,这包括使用不同的技术来构建量子比特,例如超导电路、离子阱和拓扑量子计算等。 对于进一步学习量子计算机编程的资料,您可以参考各种在线教程、学术论文和专业书籍。一些量子计算机的研究机构和公司也提供了相关的教育资源和文档。 总结起来,量子计算机编程是利用特定的编程语言和算法来设计和实现在量子计算机上运行的程序。虽然我无法提供具体的量子计算机编程的PDF文件,但您可以通过学习量子编程语言和了解量子计算机的物理实现来深入了解这个领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微小冷

请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值