CQCL / pytket-qir

Public repo for the pytket-qir package
Apache License 2.0
5 stars 1 forks source link

Generate QIR compatible with azure-quantum #152

Open cqc-alec opened 1 week ago

cqc-alec commented 1 week ago

Attempts to submit QIR generated by pytket_to_qir() via azure-quantum currently fail with

RuntimeError: Cannot retrieve results as job execution failed(status: Failed.error: {'additional_properties': {}, 'code': 'QIRPreProcessingFailed', 'message': 'No match found for output recording set'})

The same error occurs when submitting to ionq.simulator or quantinuum.sim.h1-1sc.

from azure.quantum import Workspace
workspace = Workspace(
    resource_id="...",
    location="...",
)
target = workspace.get_targets(name="ionq.simulator")
job = target.submit(
    input_data=open("test-qir.ll").read(),
    input_data_format="qir.v1",
    output_data_format="microsoft.quantum-results.v1",
    name="test-submission",
    input_params={"entryPoint": "main", "arguments": [], "count": 100},
)
job.wait_until_completed()
result = job.get_results()

test-qir.ll:

; ModuleID = 'Generated from input pytket circuit'
source_filename = "Generated from input pytket circuit"

%Qubit = type opaque
%Result = type opaque

@0 = internal constant [2 x i8] c"c\00"

define void @main() #0 {
entry:
  %0 = call i1* @create_creg(i64 2)
  call void @__quantum__qis__h__body(%Qubit* null)
  call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @mz_to_creg_bit(%Qubit* null, i1* %0, i64 0)
  call void @mz_to_creg_bit(%Qubit* inttoptr (i64 1 to %Qubit*), i1* %0, i64 1)
  call void @__quantum__rt__tuple_start_record_output()
  %1 = call i64 @get_int_from_creg(i1* %0)
  call void @__quantum__rt__int_record_output(i64 %1, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @0, i32 0, i32 0))
  call void @__quantum__rt__tuple_end_record_output()
  ret void
}

declare i1 @get_creg_bit(i1*, i64)
declare void @set_creg_bit(i1*, i64, i1)
declare void @set_creg_to_int(i1*, i64)
declare i1 @__quantum__qis__read_result__body(%Result*)
declare i1* @create_creg(i64)
declare i64 @get_int_from_creg(i1*)
declare void @mz_to_creg_bit(%Qubit*, i1*, i64)
declare void @__quantum__rt__int_record_output(i64, i8*)
declare void @__quantum__rt__tuple_start_record_output()
declare void @__quantum__rt__tuple_end_record_output()
declare void @__quantum__qis__h__body(%Qubit*)
declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)

attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="2" "required_num_results"="2" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}
cqc-melf commented 1 week ago

I think this is expected, because of the use of create_creg and friends, and the use of __quantum__rt__tuple_start_record_output .

Should we split this up into several subtasks?

cqc-alec commented 1 week ago

I think this is expected, because of the use of create_creg and friends, and the use of __quantum__rt__tuple_start_record_output .

That was my guess too.

But I note that submitting the following QIR to quantinuum.sim.h1-1e via azure-quantum does work:

; ModuleID = 'qiskit-qir.bc'
source_filename = "circuit-171"

%Qubit = type opaque
%Result = type opaque

define void @circuit-171() #0 {
entry:
  call void @__quantum__rt__initialize(i8* null)
  call void @__quantum__qis__h__body(%Qubit* null)
  call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
  call void @__quantum__rt__array_record_output(i64 2, i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
  call void @__quantum__rt__result_record_output(%Result* null, i8* null)
  ret void
}

declare void @__quantum__rt__initialize(i8*)
declare void @__quantum__qis__h__body(%Qubit*)
declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
declare void @__quantum__rt__array_record_output(i64, i8*)
declare void @__quantum__rt__result_record_output(%Result*, i8*)

attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="2" "required_num_results"="2" }
attributes #1 = { "irreversible" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}

So I wonder if those functions are actually necessary, at least for this simple case...

cqc-alec commented 1 week ago

Apparently there is some magic QIR conversion going on behind the scenes.

cqc-melf commented 1 week ago

Not sure what you wanted to show with the example? Yes it is not using the functions that are problematic?

I think we should generally try to upgrade everything to not use them? Or what do you mean?

cqc-melf commented 1 week ago

Apparently there is some magic QIR conversion going on behind the scenes.

I think the magic is that it updates the results handling which is required in a non profile way by the device, but sending that off to azure will be rejected for now? At least it sounded like that?

cqc-alec commented 1 week ago

Not sure what you wanted to show with the example? Yes it is not using the functions that are problematic?

I was surprised that it worked, because I thought quantinuum needed to use those other (non-standard) methods.

I think we should generally try to upgrade everything to not use them? Or what do you mean?

Yes agreed that should be the goal.

cqc-melf commented 4 days ago

I think it would be helpful to add more subtasks for this. One for adding the phi node generation and one for updating the result recording. Should I do that @cqc-alec ?

cqc-alec commented 3 days ago

I think it would be helpful to add more subtasks for this. One for adding the phi node generation and one for updating the result recording. Should I do that @cqc-alec ?

It's not currently clear to me exactly what the subtasks are, but yes if you can break it down that would be great.