동적 회로
동적 회로를 사용하면 회로 실행 중에 큐비트를 측정하고, 그 측정 결과를 바탕으로 후속 연산을 제어할 수 있습니다. Qiskit은 동적 회로의 구축 및 추론에 대한 포괄적인 지원을 제공합니다. 자세한 내용은 ‘고전적 피드포워드 및 제어 흐름’ 가이드를 참조하십시오.
Qiskit의 C API는 현재 제어 흐름 명령어와 고전적 표현식의 검사만 지원합니다. 향후 Qiskit 릴리스에서는 고전적 표현식 구성 및 제어 흐름 명령어 추가 기능이 지원될 예정입니다.
이 API를 사용할 때는 다음의 가정 사항과 제한 사항을 염두에 두시기 바랍니다:
- 제어 흐름 및 고전적 표현식 API가 반환하는 대부분의 객체는 읽기 전용 포인터로 빌려온 것들입니다(로 반환됨
const *). 이러한 항목들은 부모 객체(예를 들어,IfElse명령어를 소유하고 있는 회로)가 존재하는 동안에만 유효합니다. 따라서 호출자는 빌린 포인터를 해제해서는 안 되며, 해당 포인터가 사용되는 기간보다 부모 객체의 수명이 더 길도록 보장해야 합니다. - 이 API는 오류 코드를 사용하지 않습니다. 올바르게 호출될 경우, 이 함수들은 절대 오류가 발생하지 않습니다. 그러나 변이체별 함수(예:
qk_control_flow_box_duration_kind()(해당 명령어가Box명령을 기대하는 경우)는 잘못된 유형의 객체와 함께 사용될 경우 패닉을 일으키고 해당 프로세스를 중단합니다. 이를 방지하기 위해, 해당 변형에 특화된 함수를 호출하기 전에 객체의 유형이나 종류를 확인하는 일련의 쿼리 함수가 제공됩니다. - Qiskit은 고차 정수를 사용하여 일부 제어 흐름 및 고전적인 표현식 구조(예: 고전적인 레지스터 조건 값 및 switch case 레이블 등)를 표현합니다. 향후 C API에 큰 정수(big integer)에 대한 완전한 지원이 추가될 예정입니다. 그때까지는 이 API의 수치 값이.에 들어갈 수 있는 범위 내로 제한됩니다
uint64_t.
다음 예제 프로그램은 제어 흐름 명령어와 고전적 표현식을 검사하기 위한 모든 API 함수와 유형을 보여줄 뿐만 아니라, 선별된 고전적 레지스터 조회 함수들도 함께 보여줍니다. 시작 지점은 맨 inspect_circuit 아래에 있으며, 그 위에 정의된 헬퍼 함수들을 호출합니다.
// Forward declarations for recursive circuit inspection
void inspect_circuit(const QkCircuit *, const QkControlFlowInstruction *, int);
void inspect_register(const QkClassicalRegister *creg, int indent) {
size_t num_bits = qk_classical_register_num_bits(creg);
char *reg_name = qk_classical_register_name(creg);
printf("%*sClassical Register: name='%s', num_bits=%zu\n", indent, "",
reg_name ? reg_name : "<unnamed>", num_bits);
qk_str_free(reg_name);
}
void inspect_expr(const QkExprNode *expr_node, int indent) {
QkExprNodeKind kind = qk_expr_kind(expr_node);
printf("%*sExpression kind: %d\n", indent, "", kind);
switch (kind) {
case QkExprNodeKind_Unary: {
QkUnaryExprInfo unary = qk_expr_unary_info(expr_node);
printf("%*sUnary operation: op=%d, type=%d\n", indent, "", unary.op, unary.ty.ty);
printf("%*sOperand:\n", indent, "");
inspect_expr(unary.operand, indent + 2);
break;
}
case QkExprNodeKind_Binary: {
QkBinaryExprInfo binary = qk_expr_binary_info(expr_node);
printf("%*sBinary operation: op=%d, type=%d\n", indent, "", binary.op, binary.ty.ty);
printf("%*sLeft operand:\n", indent, "");
inspect_expr(binary.left, indent + 2);
printf("%*sRight operand:\n", indent, "");
inspect_expr(binary.right, indent + 2);
break;
}
case QkExprNodeKind_Cast: {
QkCastExprInfo cast = qk_expr_cast_info(expr_node);
printf("%*sCast to type: %d", indent, "", cast.ty.ty);
if (cast.ty.ty == QkExprType_Uint) {
printf(" (width=%u)", cast.ty.width);
}
printf("\n%*sOperand:\n", indent, "");
inspect_expr(cast.operand, indent + 2);
break;
}
case QkExprNodeKind_Index: {
QkIndexExprInfo index = qk_expr_index_info(expr_node);
printf("%*sIndex operation, type=%d\n", indent, "", index.ty.ty);
printf("%*sTarget:\n", indent, "");
inspect_expr(index.target, indent + 2);
printf("%*sIndex:\n", indent, "");
inspect_expr(index.index, indent + 2);
break;
}
case QkExprNodeKind_Value: {
const QkValue *value = qk_expr_as_value(expr_node);
QkExprTypeInfo value_type = qk_value_type_info(value);
printf("%*sValue type: %d", indent, "", value_type.ty);
switch (value_type.ty) {
case QkExprType_Duration: {
QkDurationInfo duration_info = qk_value_duration_info(value);
if (duration_info.ty == QkDurationType_Dt) {
printf(", value=%ld dt\n", duration_info.value.dt);
} else {
printf(", value=%f (unit: %d)\n", duration_info.value.time, duration_info.ty);
}
break;
}
case QkExprType_Float: {
double float_val = qk_value_float(value);
printf(", value=%f\n", float_val);
break;
}
case QkExprType_Uint: {
uint64_t val = qk_value_uint(value);
printf(" (width=%u), value=%lu\n", value_type.width, val);
break;
}
case QkExprType_Bool: {
bool bool_val = qk_value_bool(value);
printf(", value=%s\n", bool_val ? "true" : "false");
break;
}
}
break;
}
case QkExprNodeKind_Var: {
const QkVar *var = qk_expr_as_var(expr_node);
char *name = qk_var_name(var);
QkExprTypeInfo type_info = qk_var_type_info(var);
printf("%*sVariable: name='%s', type=%d", indent, "", name ? name : "<unnamed>",
type_info.ty);
if (type_info.ty == QkExprType_Uint) {
printf(" (width=%u)", type_info.width);
}
printf("\n");
if (name != NULL) {
qk_str_free(name);
}
break;
}
case QkExprNodeKind_Stretch: {
const QkStretch *stretch = qk_expr_as_stretch(expr_node);
char *name = qk_stretch_name(stretch);
printf("%*sStretch: name='%s'\n", indent, "", name);
qk_str_free(name);
break;
}
}
}
void inspect_condition(const QkControlFlowInstruction *cf_inst, int indent) {
QkConditionType condition_type = qk_control_flow_condition_type(cf_inst);
printf("%*sCondition type: %d\n", indent, "", condition_type);
switch (condition_type) {
case QkConditionType_ClBit: {
QkConditionBitInfo cond_bit_info = qk_control_flow_condition_bit_info(cf_inst);
printf("%*sCondition on classical bit: clbit=%u, value=%s\n", indent, "",
cond_bit_info.clbit, cond_bit_info.condition ? "true" : "false");
break;
}
case QkConditionType_ClReg: {
uint64_t cond_width = qk_control_flow_condition_reg_cond_bit_width(cf_inst);
printf("%*sCondition on classical register (width=%lu bits)\n", indent, "", cond_width);
if (cond_width <= 64) {
uint64_t condition = qk_control_flow_condition_reg_cond_uint(cf_inst);
printf("%*sCondition value: %lu\n", indent, "", condition);
} else {
printf("%*sCondition value too large (>64 bits) for direct display\n", indent, "");
}
const QkClassicalRegister *creg = qk_control_flow_condition_reg(cf_inst);
inspect_register(creg, indent + 2);
break;
}
case QkConditionType_Expr: {
printf("%*sCondition based on expression:\n", indent, "");
const QkExprNode *expr = qk_control_flow_condition_expr(cf_inst);
inspect_expr(expr, indent + 2);
break;
}
}
}
void inspect_box(const QkControlFlowInstruction *cf_inst, int indent) {
printf("%*sInspecting Box instruction\n", indent, "");
QkBoxDurationKind duration_type = qk_control_flow_box_duration_kind(cf_inst);
switch (duration_type) {
case QkBoxDurationKind_NoDuration:
printf("%*sNo duration specified\n", indent, "");
break;
case QkBoxDurationKind_Duration: {
QkDurationInfo duration_info = qk_control_flow_box_duration_val_info(cf_inst);
printf("%*sDuration: ", indent, "");
if (duration_info.ty == QkDurationType_Dt) {
printf("%ld dt\n", duration_info.value.dt);
} else {
printf("%f (unit: %d)\n", duration_info.value.time, duration_info.ty);
}
break;
}
case QkBoxDurationKind_Expr: {
printf("%*sDuration specified by expression:\n", indent, "");
const QkExprNode *expr = qk_control_flow_box_duration_expr(cf_inst);
inspect_expr(expr, indent + 2);
break;
}
}
}
void inspect_for_loop(const QkControlFlowInstruction *cf_inst, int indent) {
printf("%*sInspecting ForLoop instruction\n", indent, "");
QkLoopCollectionType collection_type = qk_control_flow_loop_collection_type(cf_inst);
printf("%*sCollection type: %s\n", indent, "",
collection_type == QkLoopCollectionType_List ? "List" : "Range");
switch (collection_type) {
case QkLoopCollectionType_List: {
QkLoopElements loop_elements = qk_control_flow_loop_elements(cf_inst);
printf("%*sLoop elements (%zu items): [", indent, "", loop_elements.len);
for (size_t i = 0; i < loop_elements.len; i++) {
printf("%zu%s", loop_elements.elements[i], i < loop_elements.len - 1 ? ", " : "");
}
printf("]\n");
break;
}
case QkLoopCollectionType_Range: {
int64_t start, stop, step;
qk_control_flow_loop_range(cf_inst, &start, &stop, &step);
printf("%*sLoop range: start=%ld, stop=%ld, step=%ld\n", indent, "", start, stop, step);
break;
}
}
// Inspect the loop parameter, if it exists
QkLoopParamKind param_kind = qk_control_flow_loop_param_kind(cf_inst);
switch (param_kind) {
case QkLoopParamKind_NoLoopParam:
printf("%*sNo loop parameter\n", indent, "");
break;
case QkLoopParamKind_Parameter: {
QkSymbolInfo symbol_info = qk_control_flow_loop_symbol_info(cf_inst);
printf("%*sLoop parameter (Symbol): ", indent, "");
if (symbol_info.ty == QkSymbolType_Standalone) {
printf("name='%s'\n", symbol_info.name ? symbol_info.name : "<unnamed>");
} else if (symbol_info.ty == QkSymbolType_Element) {
printf("element index=%zu\n", symbol_info.index);
}
qk_str_free(symbol_info.name);
break;
}
case QkLoopParamKind_Variable: {
const QkVar *var = qk_control_flow_loop_variable(cf_inst);
char *name = qk_var_name(var);
QkExprTypeInfo type_info = qk_var_type_info(var);
printf("%*sLoop parameter (Variable): name='%s', type=%d", indent, "",
name ? name : "<unnamed>", type_info.ty);
if (type_info.ty == QkExprType_Uint) {
printf(" (width=%u)", type_info.width);
}
printf("\n");
if (name != NULL) {
qk_str_free(name);
}
break;
}
}
}
void inspect_switch(const QkControlFlowInstruction *cf_inst, int indent) {
printf("%*sInspecting Switch instruction\n", indent, "");
// Inspect the Switch instruction target
QkConditionType target_type = qk_control_flow_switch_target_type(cf_inst);
printf("%*sTarget type: %d\n", indent, "", target_type);
switch (target_type) {
case QkConditionType_ClBit: {
uint32_t bit = qk_control_flow_switch_target_bit(cf_inst);
printf("%*sTarget bit: %u\n", indent, "", bit);
break;
}
case QkConditionType_ClReg: {
printf("%*sTarget register:\n", indent, "");
const QkClassicalRegister *creg = qk_control_flow_switch_target_register(cf_inst);
inspect_register(creg, indent + 2);
break;
}
case QkConditionType_Expr: {
printf("%*sTarget expression:\n", indent, "");
const QkExprNode *expr = qk_control_flow_switch_target_expr(cf_inst);
inspect_expr(expr, indent + 2);
break;
}
}
// Inspect the Switch instruction cases
size_t num_cases = qk_control_flow_switch_num_cases(cf_inst);
printf("%*sNumber of cases: %zu\n", indent, "", num_cases);
for (size_t case_idx = 0; case_idx < num_cases; case_idx++) {
printf("%*sCase %zu:\n", indent, "", case_idx);
uint64_t bit_width = qk_control_flow_switch_case_labels_bit_width(cf_inst, case_idx);
if (bit_width <= 64) {
QkSwitchCaseLabels labels = qk_control_flow_switch_case_labels_uint(cf_inst, case_idx);
printf("%*sLabels (%zu): [", indent + 2, "", labels.num_labels);
for (size_t label = 0; label < labels.num_labels; label++) {
printf("%lu%s", labels.labels[label], label < labels.num_labels - 1 ? ", " : "");
}
printf("]\n");
if (labels.num_labels > 0) {
qk_control_flow_switch_case_labels_clear(&labels);
}
} else {
printf("%*sLabel width (%lu bits) too large for direct display\n", indent + 2, "",
bit_width);
}
if (qk_control_flow_switch_is_case_default(cf_inst, case_idx)) {
printf("%*sThis is the DEFAULT case\n", indent + 2, "");
}
}
}
void inspect_control_flow_instruction(const QkControlFlowInstruction *cf_inst, int indent) {
QkControlFlowKind cf_type = qk_control_flow_kind(cf_inst);
printf("%*s=== Control Flow: kind - %d ===\n", indent, "", cf_type);
switch (cf_type) {
case QkControlFlowKind_Box:
inspect_box(cf_inst, indent + 2);
break;
case QkControlFlowKind_BreakLoop:
printf("%*sBreak loop instruction\n", indent + 2, "");
break;
case QkControlFlowKind_ContinueLoop:
printf("%*sContinue loop instruction\n", indent + 2, "");
break;
case QkControlFlowKind_ForLoop:
inspect_for_loop(cf_inst, indent + 2);
break;
case QkControlFlowKind_IfElse:
printf("%*sInspecting IfElse instruction\n", indent + 2, "");
inspect_condition(cf_inst, indent + 2);
break;
case QkControlFlowKind_While:
printf("%*sInspecting While instruction\n", indent + 2, "");
inspect_condition(cf_inst, indent + 2);
break;
case QkControlFlowKind_Switch:
inspect_switch(cf_inst, indent + 2);
break;
}
size_t num_blocks = qk_control_flow_num_blocks(cf_inst);
printf("%*sNumber of blocks: %zu\n", indent, "", num_blocks);
for (size_t block = 0; block < num_blocks; block++) {
printf("%*s--- Block %zu ---\n", indent, "", block);
const QkCircuit *block_circuit = qk_control_flow_block_circuit(cf_inst, block);
// Go deeper in the hierarchy
inspect_circuit(block_circuit, cf_inst, indent + 2);
}
}
void inspect_circuit(const QkCircuit *circuit, const QkControlFlowInstruction *parent_cf,
int indent) {
size_t num_instructions = qk_circuit_num_instructions(circuit);
printf("%*sCircuit has %zu instructions\n", indent, "", num_instructions);
for (size_t inst_idx = 0; inst_idx < num_instructions; inst_idx++) {
QkCircuitInstruction inst;
qk_circuit_get_instruction(circuit, inst_idx, &inst);
QkOperationKind kind = qk_circuit_instruction_kind(circuit, inst_idx);
if (kind == QkOperationKind_ControlFlow) {
QkControlFlowInstruction *cf_inst =
qk_circuit_get_control_flow_instruction(circuit, inst_idx, parent_cf);
inspect_control_flow_instruction(cf_inst, indent);
qk_control_flow_instruction_free(cf_inst);
} else {
printf("%*sInstruction %zu: Standard gate/operation\n", indent, "", inst_idx);
// Inspect qubit mapping, if one exists
const uint32_t *qubit_mapping = parent_cf ? qk_control_flow_qubit_map(parent_cf) : NULL;
if (inst.num_qubits > 0) {
printf("%*s Qubits: [", indent, "");
for (uint32_t qubit = 0; qubit < inst.num_qubits; qubit++) {
uint32_t mapped_qubit =
qubit_mapping ? qubit_mapping[inst.qubits[qubit]] : inst.qubits[qubit];
printf("%u%s", mapped_qubit, qubit < inst.num_qubits - 1 ? ", " : "");
}
printf("]\n");
}
// Inspect clbit mapping, if one exists
const uint32_t *clbit_mapping = parent_cf ? qk_control_flow_clbit_map(parent_cf) : NULL;
if (inst.num_clbits > 0) {
printf("%*s Clbits: [", indent, "");
for (uint32_t clbit = 0; clbit < inst.num_clbits; clbit++) {
uint32_t mapped_clbit =
clbit_mapping ? clbit_mapping[inst.clbits[clbit]] : inst.clbits[clbit];
printf("%u%s", mapped_clbit, clbit < inst.num_clbits - 1 ? ", " : "");
}
printf("]\n");
}
}
qk_circuit_instruction_clear(&inst);
}
}C API 함수 및 유형에 대한 자세한 내용은 ‘제어 흐름’ 및 ‘고전적 표현식’ 문서 페이지를 참조하십시오.
이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.