OriginIR 语法详解
OriginIR 是 QPanda 的原生量子程序中间表示(Intermediate Representation, IR),是 pyqpanda3 生态内序列化、传输与调试量子程序的文本格式。本章逐条详解 OriginIR 的词法与语法:程序整体结构、QINIT/CREG 声明、各类量子门、角度表达式、DAGGER/CONTROL 修饰、QIF/QWHILE 经典控制流、MEASURE/RESET 操作、自定义门,以及常见错误对照。
如何把 OriginIR 文本转换为 QProg(以及反向转换)属于"怎么用"的问题,见 IR 转换 与 convert_originir_string_to_qprog 等 API 参考;本章只回答"语法长什么样"。
1. 语法版式总览
权威语法定义
OriginIR 的权威语法由 ANTLR 词法/语法文件(.g4)定义:
originirLexer.g4(138 行):词法规则——关键字、门名 token、数字与标识符。originirParser.g4(330 行):语法规则——程序结构与各语句的产生式。
pyqpanda3 0.4.1 发行版内置的转译器(intermediate_compiler 模块)实现的是经典方言:它与 .g4 在 QINIT/CREG、门声明、MEASURE/RESET 等核心语法上完全一致,但在版本头、表达式、控制流与自定义门的写法上保留了传统形式(下文的示例全部经 convert_originir_string_to_qprog 实测通过)。双方言的差异逐条列在第 9 节。
程序结构
按 .g4 的 program 规则,一个 OriginIR 程序是:
program: version? statement* EOF即"可选的版本头 + 若干条语句"。每条语句属于下列种类之一(statement 规则):
| 语句种类 | 语法规则 | 示例 |
|---|---|---|
| 声明(量子比特/经典寄存器) | declaration → qinit_declaration / cinit_declaration | QINIT 2、CREG 4 |
| 量子门声明 | quantum_gate_declaration | H q[0]、RX q[0],(PI/2) |
| 测量 | measure_statement | MEASURE q[0],c[0] |
| 重置 | reset_statement | RESET q[1] |
| 经典赋值 | assign_statement | c[0]=c[0]+1(见第 5、9 节) |
| 屏障 | barrier_statement | BARRIER q[0],q[1] |
| 文件包含 | includestatement | include "other.originir"(见第 9 节) |
| 块语句 | blockstatement | DAGGER/CONTROL/QIF/QWHILE/QGATE |
最小的完整程序如下(这是全章所有例子的共同骨架):
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
CREG 1
H q[0]
CNOT q[0],q[1]
MEASURE q[0],c[0]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(prog.originir() 为往返转换:QProg 再转回 OriginIR 文本):
QINIT 2
CREG 1
H q[0]
CNOT q[0],q[1]
MEASURE q[0],c[0]本章所有示例都遵循这一模式:OriginIR 文本 → convert_originir_string_to_qprog 解析为 QProg → 打印往返文本验证。注意往返输出中的角度参数会被求值成定点小数(见第 5 节),且 CREG 会被归一化为实际用于 MEASURE 的经典比特数(最小为 1,如本节未测量时输出 CREG 1)。
2. 头部、版本声明、注释
版本头
.g4 的 program 规则允许可选版本头:
version: ORIGINIR VersionSpecifier SEMICOLON例如 ORIGINIR 1.0;。但 pyqpanda3 0.4.1 的转译器尚未实现版本头解析,实测报错如下(错误信息为运行时原文,下同):
ORIGINIR 1.0;
QINIT 2
H q[0]运行结果:
Error:
<Expected> OriginIR Statement
<Problem> The string is invalid originir string.It's Identifier (ORIGINIR)
<Result> Exit.因此 0.4.1 中编写 OriginIR 程序时不要写版本头,直接从 QINIT 开始。
注释
词法器支持 C++ 风格的两种注释:// 单行注释与 /* */ 块注释(LineComment/BlockComment 规则),两者都会被跳过,可出现在任意位置:
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
// line comment
/* block
comment */
H q[0] // trailing comment
CNOT q[0],q[1]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 1
H q[0]
CNOT q[0],q[1]语句分隔
0.4.1 的方言以换行分隔语句(NEWLINE 被跳过、可空行),不接受分号。.g4 要求每条语句后跟分号,但 0.4.1 实测对分号直接报错:
QINIT 2
H q[0];运行结果:
Error:
<Expected> OriginIR Statement
<Problem> The string is invalid originir string.It's ;
<Result> Exit.关键字大小写
关键字严格区分大小写(Identifier 规则为 [a-zA-Z_][a-zA-Z_0-9]*,QINIT 等关键字为大写 token)。qinit 不会被识别:
qinit 2
H q[0]运行结果:
Error:
<Expected> OriginIR Statement
<Problem> The string is invalid originir string.It's Identifier (qinit)
<Result> Exit.3. QINIT / CREG 声明
QINIT 申请量子比特,CREG 申请经典寄存器,格式均为"关键字 + 空格 + 数量":
qinit_declaration : QINIT_KEY Integer_Literal ;
cinit_declaration : CREG_KEY Integer_Literal ;数量必须是非负整数(Integer_Literal: [1-9][0-9]* | '0',即无前导零)。在 0.4.1 中两者都必须位于使用之前:
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 4
CREG 4
H q[0]
H q[1]
H q[2]
H q[3]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 4
CREG 1
H q[0]
H q[1]
H q[2]
H q[3]引用单个比特与整个比特数组
- 单个量子比特用
q[i],i为下标(index: LBRACK Integer_Literal RBRACK,必须是整数常量,见第 9 节关于q[c[0]]的对照)。 - 部分单比特门与
MEASURE也接受裸的q,表示整个比特数组(展开为逐比特操作):
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
H q"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(H q 展开为对每个比特的 H):
QINIT 3
CREG 1
H q[0]
H q[1]
H q[2]MEASURE q,c 要求量子比特总数与经典寄存器总数一致(详见第 7 节)。
常见错误:数量不匹配
MEASURE q,c 的比特数与寄存器数不一致时:
QINIT 2
CREG 3
MEASURE q,c运行结果:
Error: For "MEASURE q c", qbits' total num should be same as cbits'. Here, they are different.未声明 CREG 就测量:
QINIT 1
MEASURE q[0],c[0]运行结果:
add_measure_literal too little cbits is allocated4. 单比特、双比特与三比特门
quantum_gate_declaration 按"比特数 × 参数个数"把门分成 10 类。下表列出词法器中的门 token 及其所属类别(.g4 的 single_gate_without_parameter_type 等规则);官方教程列出、但 .g4 与 0.4.1 行为不一致的项(CP/RZX/RXX/RYY/RZZ/ECHO/ISWAPTHETA/NOT)见第 9 节。
| 类别 | 语法规则 | 门 |
|---|---|---|
| 单比特无参 | single_gate_without_parameter_type | H T S X Y Z X1 Y1 Z1 I |
| 单比特单参 | single_gate_with_one_parameter_type | RX RY RZ U1 ECHO |
| 单比特双参 | single_gate_with_two_parameter_type | U2 RPhi |
| 单比特三参 | single_gate_with_three_parameter_type | U3 |
| 单比特四参 | single_gate_with_four_parameter_type | U4 |
| 双比特无参 | double_gate_without_parameter_type | CNOT CZ ISWAP SQISWAP SWAP |
| 双比特单参 | double_gate_with_one_parameter_type | ISWAPTHETA CR(0.4.1 另接受 CP RZX RXX RYY RZZ) |
| 双比特四参 | double_gate_with_four_parameter_type | CU |
| 三比特无参 | triple_gate_without_parameter_type | TOFFOLI |
通用格式:
- 无参门:
门 q[i](单比特)或门 q[i],q[j](双比特)/门 q[i],q[j],q[k](三比特); - 有参门:
门 q[i],(p1,p2,...),参数用圆括号括起、逗号分隔(参数写法见第 5 节)。
单比特无参门
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
H q[0]
X q[1]
T q[2]
I q[0]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 3
CREG 1
H q[0]
X q[1]
T q[2]
I q[0]单比特单参门
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
RX q[0],(PI/2)
RY q[1],(0.3)
RZ q[2],(-0.5)
U1 q[0],(PI)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(注意角度被求值):
QINIT 3
CREG 1
RX q[0],(1.57079633)
RY q[1],(0.30000000)
RZ q[2],(-0.50000000)
U1 q[0],(3.14159265)单比特双参门(U2 / RPhi)
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
U2 q[0],(PI/2,-PI/3)
RPhi q[1],(0.5,1.5)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 1
U2 q[0],(1.57079633,-1.04719755)
RPhi q[1],(0.50000000,1.50000000)单比特三参门(U3)
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 1
U3 q[0],(PI/2,PI/3,PI/4)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 1
CREG 1
U3 q[0],(1.57079633,1.04719755,0.78539816)单比特四参门(U4)
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 1
U4 q[0],(0.1,0.2,0.3,0.4)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 1
CREG 1
U4 q[0],(0.10000000,0.20000000,0.30000000,0.40000000)双比特无参门
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 4
CNOT q[0],q[1]
CZ q[1],q[2]
ISWAP q[2],q[3]
SQISWAP q[0],q[3]
SWAP q[1],q[2]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 4
CREG 1
CNOT q[0],q[1]
CZ q[1],q[2]
ISWAP q[2],q[3]
SQISWAP q[0],q[3]
SWAP q[1],q[2]双比特单参门
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
CR q[0],q[1],(PI/4)
RZX q[0],q[1],(0.5)
RXX q[0],q[1],(0.5)
RYY q[0],q[1],(0.5)
RZZ q[0],q[1],(0.5)
CP q[0],q[1],(0.5)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(CP 在往返输出中被重新序列化为 CR,见第 9 节):
QINIT 2
CREG 1
CR q[0],q[1],(0.78539816)
RZX q[0],q[1],(0.50000000)
RXX q[0],q[1],(0.50000000)
RYY q[0],q[1],(0.50000000)
RZZ q[0],q[1],(0.50000000)
CR q[0],q[1],(0.50000000)双比特四参门(CU)
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
CU q[0],q[1],(0.1,0.2,0.3,0.4)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 1
CU q[0],q[1],(0.10000000,0.20000000,0.30000000,0.40000000)三比特门(TOFFOLI)
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
TOFFOLI q[0],q[1],q[2]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(TOFFOLI 在往返输出中反解为受控 X 块,见第 6 节的 CONTROL):
QINIT 3
CREG 1
CONTROL q[0],q[1]
X q[2]
ENDCONTROLECHO(单参门)
.g4 的 single_gate_with_one_parameter_type 包含 ECHO,0.4.1 同样支持:
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 1
ECHO q[0],(0.5)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 1
CREG 1
ECHO q[0],(0.50000000)5. 表达式与常量
常量
constant 规则只有三类:
constant : Integer_Literal | Double_Literal | PI ;即整数(无前导零)、小数(如 0.5、-3.141593)与 PI。
角度参数表达式
所有带角度的门,参数都写在圆括号内:门 q[i],(expr1,expr2,...)。0.4.1 在解析时直接求值角度表达式,支持 + - * / 四则运算、圆括号与一元负号;求值结果以定点小数写入往返输出(默认 8 位小数):
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
RX q[0],(PI/2)
RX q[1],(1+2*3)
RX q[2],(-PI/2)
RY q[0],(2*PI/3)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(1+2*3 求值为 7,2*PI/3 求值为 2.09439510):
QINIT 3
CREG 1
RX q[0],(1.57079633)
RX q[1],(7.00000000)
RX q[2],(-1.57079633)
RY q[0],(2.09439510).g4 的 constant_expression 规则形式上只允许"常量 op 常量"(单个运算,constant_expression: constant | constant arithmetic_op constant | arithmetic_op constant),实测 0.4.1 的角度求值器比它更宽松,接受任意长度的算术链(如上面的 1+2*3、2*PI/3)。
标识符只能作为自定义门形参出现(见第 8 节);在顶层写未定义标识符(如 RX q[0],(theta))会在求值时失败。
经典表达式与赋值:0.4.1 暂不支持
.g4 定义了完整的经典表达式链与赋值语句(expression → logical_or_expression → … → primary_expression,以及 assign_statement: c_KEY_declaration ASSIGN logical_or_expression),可用于 QIF/QWHILE 条件与 c[0]=c[0]+1 这类赋值。0.4.1 未实现经典表达式(官方教程亦标注"经典表达式目前暂不支持"),实测报错如下:
QINIT 1
CREG 2
c[0]=c[0]+1运行结果(解析错误打印到 stderr,抛出的异常为 Unknown exception):
Error at line 3, column 6: Expected expression, got c.Unknown exceptionQINIT 5
CREG 5
QWHILE c[0]<5
H q[c[0]]
QENDWHILE运行结果:
Error:
<Expected> OriginIR Statement
<Problem> The string is invalid originir string.It's <
<Result> Exit.0.4.1 中 QIF/QWHILE 的条件只能是"已测量的经典比特列表"形式,见第 7 节。
6. DAGGER / CONTROL 修饰
DAGGER 对一组门做转置共轭(求逆),CONTROL 为一组门添加控制比特。.g4 的现行形式是块语法:
dagger_statement : DAGGER_KEY LBRACE statement* RBRACE ;
control_statement : CONTROL_KEY controlbit_list LBRACE statement* RBRACE ;0.4.1 同时接受传统形式(DAGGER … ENDDAGGER、CONTROL ctrlbit_list … ENDCONTROL)与上述块形式(DAGGER { ... }、CONTROL q[i] { ... })。
传统形式 DAGGER / ENDDAGGER
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
DAGGER
H q[0]
CNOT q[0],q[1]
ENDDAGGER"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(0.4.1 往返输出时每个门单独输出一个 DAGGER 块):
QINIT 2
CREG 1
DAGGER
CNOT q[0],q[1]
ENDDAGGER
DAGGER
H q[0]
ENDDAGGER块形式 DAGGER { ... }
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
DAGGER {
H q[0]
CNOT q[0],q[1]
}"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 1
DAGGER
CNOT q[0],q[1]
ENDDAGGER
DAGGER
H q[0]
ENDDAGGER传统形式 CONTROL / ENDCONTROL
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
CONTROL q[2]
H q[0]
CNOT q[0],q[1]
ENDCONTROL"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 3
CREG 1
CONTROL q[2]
H q[0]
ENDCONTROL
CONTROL q[2]
CNOT q[0],q[1]
ENDCONTROL多个控制比特
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
CONTROL q[1],q[2]
H q[0]
ENDCONTROL"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 3
CREG 1
CONTROL q[1],q[2]
H q[0]
ENDCONTROL切勿混用块形式与传统结束符
实测(pyqpanda3 0.4.1)DAGGER { ... } 后再接 ENDDAGGER(或 CONTROL { ... } 后再接 ENDCONTROL)会使解析器陷入死循环(无限挂起)。请使用 DAGGER { ... } 或 DAGGER ... ENDDAGGER 之一,不要同时使用。
7. QIF / QWHILE 经典控制流与 MEASURE / RESET
.g4 的现行语法把条件写成圆括号表达式 + 块:
qif_statement : QIF_KEY LPAREN expression RPAREN LBRACE statement* RBRACE qelse_statement_fragment? ;
qwhile_statement : QWHILE_KEY LPAREN expression RPAREN LBRACE statement* RBRACE ;0.4.1 实现的是传统形式:QIF c[i],c[j] ... QENDIF 与 QWHILE c[i] ... QENDWHILE,条件为逗号分隔的经典比特列表(不能写表达式,见第 5、9 节)。
QIF / QELSE / QENDIF
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
CREG 2
X q[0]
MEASURE q[0],c[0]
QIF c[0]
Y q[1]
QELSE
Z q[1]
QENDIF
MEASURE q[1],c[1]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 2
X q[0]
MEASURE q[0],c[0]
QIF c[0]
Y q[1]
QELSE
Z q[1]
QENDIF
MEASURE q[1],c[1]多条件分支:QELSEIF
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 4
CREG 4
X q[0]
QIF c[0]
Y q[1]
QELSEIF c[1]
Z q[2]
QELSE
I q[3]
QENDIF"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 4
CREG 1
X q[0]
QIF c[0]
Y q[1]
QELSEIF c[1]
Z q[2]
QELSE
I q[3]
QENDIF多条件比特:QIF c[0],c[1]
条件可列出多个经典比特(官方教程的写法)。按官方教程的模型,这些比特同时为真时进入分支:
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 3
CREG 3
QIF c[0],c[1]
X q[2]
QENDIF"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 3
CREG 1
QIF c[0],c[1]
X q[2]
QENDIFQWHILE / QENDWHILE
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
CREG 2
X q[1]
QWHILE c[1]
X q[0]
X q[1]
MEASURE q[1],c[1]
QENDWHILE
MEASURE q[0],c[0]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 2
X q[1]
QWHILE c[1]
X q[0]
X q[1]
MEASURE q[1],c[1]
QENDWHILE
MEASURE q[0],c[0]QWHILE 的条件比特必须在循环开始前已通过 MEASURE 置位,且循环体必须包含改变条件比特的测量,否则循环无法结束(官方教程的写法即先 X q[1] 再在循环体内 MEASURE q[1],c[1])。
0.4.1 执行语义提示
实测(pyqpanda3 0.4.1,CPUQVM):经 convert_originir_string_to_qprog 解析出的 QIF/QWHILE,在 QVM 上运行时条件分支不会触发——解析与往返转换都正常,但分支体不执行。下面的例子先把 q[0] 置 1 并测量(c[0]=1),再 QIF c[0] 对 q[0] 再施加 X,最后测量:
from pyqpanda3.core import CPUQVM
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 1
CREG 1
X q[0]
MEASURE q[0],c[0]
QIF c[0]
X q[0]
QENDIF
MEASURE q[0],c[0]"""
machine = CPUQVM()
machine.run(prog=convert_originir_string_to_qprog(src), shots=16)
print(machine.result().get_counts())运行结果(若分支触发,第二次测量应为 '0';实测仍为 '1',分支未执行):
{'1': 16}而用核心 API 构建的等价程序(qif 结构)分支正常执行,测量结果为 {'0': 16}。若需要在 0.4.1 中执行动态线路,请使用核心 API 的 qif/qelse/qwhile(见 动态线路 教程)。get_counts() 返回的比特串从左到右对应 c[n-1] … c[0];0.4.1 上实测,该约定对 OriginIR 解析的程序与核心 API(measure/qif)构建的程序均成立(例如 X q[1] 后接 measure([0,1],[0,1]) 返回 '10')。
MEASURE 操作
MEASURE 测量量子比特并把结果写入经典寄存器(measure_statement 规则:MEASURE_KEY q_KEY_declaration COMMA c_KEY_declaration):
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 1
CREG 1
H q[0]
MEASURE q[0],c[0]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 1
CREG 1
H q[0]
MEASURE q[0],c[0]当量子比特数与经典寄存器数相同时,可用裸的 q,c 一次测量全部(MEASURE_KEY Q_KEY COMMA C_KEY,展开为逐比特测量,见第 3 节示例);数量不一致时报错见第 3 节。
RESET 操作(语法支持,0.4.1 转换暂不支持)
.g4 有 reset_statement 规则(RESET_KEY q_KEY_declaration | RESET_KEY Q_KEY),0.4.1 可以解析,但转换为 QProg 时暂不支持,实测打印警告后失败(警告为运行时原文,含源码中的拼写 Warrnig):
QINIT 2
RESET q[1]运行结果:
Compiler | BuildQProg.h | QProgNodeCollector | add_reset_literal | Warrnig: The Reset operation will be ok in future.Now, it doesn't work.Exit.Caught an unknown exception!8. 自定义门声明与作用域
.g4 的现行形式是 QGATE 门名(形参列表) { 门体 }(gate_func_statement 规则);0.4.1 实现的是传统形式:
QGATE name qubit_formal_params,(angle_formal_params)
body (calls to built-in gates or previously defined custom gates)
ENDQGATE门体语句同样以换行分隔、不带分号。自定义门的调用方式与内置门一致:门名 q[0],q[1] 或 门名 q[0],(角度实参),实参在调用处求值并代入门体。
基本自定义门
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
QGATE new_H a,b
Y a
Z b
ENDQGATE
new_H q[0],q[1]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(自定义门调用在往返输出中被内联展开):
QINIT 2
CREG 1
Y q[0]
Z q[1]带角度形参的自定义门
角度形参写在圆括号内,门体内的角度表达式可引用形参(如 PI/2+b),调用时用实参求值:
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
QGATE new_RX a,(b)
RX a,(PI/2+b)
X a
ENDQGATE
new_RX q[1],(PI/4)"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果(PI/2+b = PI/2 + PI/4 = 2.35619449,实参代入后求值):
QINIT 2
CREG 1
RX q[1],(2.35619449)
X q[1]门体嵌套调用自定义门
门体可以调用此前定义的自定义门:
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
QGATE inner a
H a
ENDQGATE
QGATE outer a,b
inner a
X b
ENDQGATE
outer q[0],q[1]"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 1
H q[0]
X q[1]用裸 q 调用自定义门
当比特形参数与量子比特总数一致时,调用处可用裸 q:
from pyqpanda3.intermediate_compiler import convert_originir_string_to_qprog
src = """QINIT 2
QGATE new_2 a,b
H a
X b
ENDQGATE
new_2 q"""
prog = convert_originir_string_to_qprog(src)
print(prog.originir())运行结果:
QINIT 2
CREG 1
H q[0]
X q[1]实参数量不匹配
调用时比特实参数与形参数不一致会报错:
QINIT 2
QGATE new_H a
H a
ENDQGATE
new_H q[0],q[1]运行结果:
IRQProgNodeCollectorParser | parse_custom_gate_call_statement | Qubit parameter count of new_H (i.e. Custom gate) mismatch.作用域与命名约束
- 形参名只在门体内有效(角度形参可出现在门体内的角度表达式中);门体外的语句无法引用门体形参。
- 形参名不能与关键字冲突(
.g4注释中的原话:自定义门的形参名不能与相关关键字冲突)。 - 0.4.1 转换自定义门时会在
stderr打印调试信息(Custom Gate: 门名、Qbit Params: ...、Gate Operations: ...),不影响转换结果。
9. 常见错误对照(词法与语法层)
本节把".g4 权威语法"与"pyqpanda3 0.4.1 实测行为"逐条对照。convert_originir_string_to_qprog 对不合法文本抛出的异常信息多为运行时原文(Unknown exception 为 0.4.1 对部分解析错误的统一转译;更具体的解析错误会打印到 stderr)。所有对照以第 1 节的 .g4 词法/语法文件为权威基准。
| # | 构造 | .g4(权威语法) | pyqpanda3 0.4.1 实测 |
|---|---|---|---|
| 1 | ORIGINIR 1.0; 版本头 | program: version? statement*,支持 | 报错 It's Identifier (ORIGINIR),勿写版本头 |
| 2 | include "file" | includestatement,支持 | 报错 It's EOF(0.4.1 未实现文件包含) |
| 3 | 语句尾分号 ; | 每条 statement 后必须有 SEMICOLON | 报错 It's ;,以换行分隔语句 |
| 4 | QIF (expr) { ... } | qif_statement 现行形式 | stderr:Expected 'c', got '(',异常 Unknown exception |
| 5 | QWHILE (expr) { ... } | qwhile_statement 现行形式 | 异常 Unknown exception |
| 6 | QGATE name(params) { ... } | gate_func_statement 现行形式 | stderr:Expected 'Identifier', got '(',异常 Unknown exception |
| 7 | 经典赋值 c[0]=c[0]+1 | assign_statement,支持 | 异常 Unknown exception(经典表达式暂不支持) |
| 8 | 条件比较 QWHILE c[0]<5 / QIF c[0]==1 | expression 支持比较运算 | 报错 It's < / It's ==,条件只能为 c[i] 列表 |
| 9 | 下标表达式 q[c[0]] | index: LBRACK Integer_Literal RBRACK,仅整数常量 | stderr:Expected expression, got c,异常 Unknown exception |
| 10 | NOT q[0] | 词法器有 NOT_GATE token,但无任何 _type 规则引用它 | 报错 It's NOT |
| 11 | ISWAPTHETA q[0],q[1],(0.5) | double_gate_with_one_parameter_type 含 ISWAPTHETA | 解析通过,转换报错 ISWAPTHETA is not supported by QGate. exit. |
| 12 | RESET q[1] | reset_statement,支持 | 解析通过,转换警告 The Reset operation will be ok in future.Now, it doesn't work.Exit. 后失败 |
| 13 | CP / RZX / RXX / RYY / RZZ | 词法器仅收录 CP_GATE(同样未被任何 _type 规则引用);RZX 等无对应 token | 0.4.1 全部可解析执行;CP 往返输出时被序列化为 CR |
| 14 | ECHO q[0],(0.5) | single_gate_with_one_parameter_type 含 ECHO | 正常支持 |
| 15 | 传统控制流结束符 QENDIF/QENDWHILE/ENDQGATE/ENDDAGGER/ENDCONTROL | 词法器有对应 token,但 parser 规则未引用(qif_statement 仅 ELSE) | 0.4.1 传统方言的组成部分,正常支持 |
| 16 | DAGGER { ... } 后接 ENDDAGGER(混用) | — | 解析器无限挂起(实测死循环),切勿混用 |
| 17 | QIF c[0] 分支在 CPUQVM 上的执行 | — | 经 OriginIR 解析的分支不触发(实测);核心 API qif 构建的等价程序正常 |
典型错误文本(原文):
Error:
<Expected> OriginIR Statement
<Problem> The string is invalid originir string.It's Identifier (ORIGINIR)
<Result> Exit.Error:
<Expected> OriginIR Statement
<Problem> The string is invalid originir string.It's ;
<Result> Exit.Error at line 3, column 5: Expected 'c', got '('.
Expected(int) '132', got(int) '58'.Error at line 2, column 10: Expected 'Identifier', got '('.
Expected(int) '113', got(int) '58'.Error at line 3, column 5: Expected expression, got c.current identifier:theta
Error: <Pos>:Statement.hpp >IdentifierExpression > getFPBuildQProg | QProgNodeCollector | add_qgate |ISWAPTHETA is not supported by QGate. exit.Compiler | BuildQProg.h | QProgNodeCollector | add_reset_literal | Warrnig: The Reset operation will be ok in future.Now, it doesn't work.Exit.IRQProgNodeCollectorParser | parse_custom_gate_call_statement | Qubit parameter count of new_H (i.e. Custom gate) mismatch.相关章节
- 转换接口的使用方法:IR 转换(OriginIR 与 QASM)
- 转换函数 API 参考:convert_originir_string_to_qprog 等
- 需要执行动态线路(
qif/qwhile):动态线路