Closed cqc-alec closed 10 months ago
I checked the QIR and I believe it represents the circuit:
PhasedX(3.5, 0.5, 0)
PhasedX(0.5, 0.5, 1)
ZZPhase(0.5, 0, 1)
Rz(3.0, 0)
PhasedX(0.5, 0.0, 1)
which ought to yield the (0,0)/(1,1) results. (It isn't unitarily equivalent to the original circuit because an Rz gate before a measure has been removed, which shouldn't affect the result.)
As confirmation, the unitary of the above circuit is:
[[ 0.5+0.5j 0. -0.j 0.5+0.5j 0. -0.j ]
[ 0. +0.j -0.5+0.5j 0. +0.j -0.5+0.5j]
[-0. +0.j 0.5-0.5j 0. -0.j -0.5+0.5j]
[ 0.5+0.5j 0. +0.j -0.5-0.5j -0. -0.j ]]
The first column is equally weighted between (0,0) and (1,1).
The QIR:
; ModuleID = 'c0'
source_filename = "c0"
%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__phasedx__body(double 0x4025FDBBE9BBA775, double 0x3FF921FB54442D18, %Qubit* null)
call void @__quantum__qis__phasedx__body(double 0x3FF921FB54442D18, double 0x3FF921FB54442D18, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rzz__body(double 0x3FF921FB54442D18, %Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rz__body(double 0x4022D97C7F3321D2, %Qubit* null)
call void @__quantum__qis__phasedx__body(double 0x3FF921FB54442D18, double 0.000000e+00, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
%1 = call i1 @__quantum__qis__read_result__body(%Result* null)
call void @set_creg_bit(i1* %0, i64 0, i1 %1)
call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
%2 = call i1 @__quantum__qis__read_result__body(%Result* inttoptr (i64 1 to %Result*))
call void @set_creg_bit(i1* %0, i64 1, i1 %2)
call void @__quantum__rt__tuple_start_record_output()
%3 = call i64 @get_int_from_creg(i1* %0)
call void @__quantum__rt__int_record_output(i64 %3, 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 @__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__phasedx__body(double, double, %Qubit*)
declare void @__quantum__qis__rzz__body(double, %Qubit*, %Qubit*)
declare void @__quantum__qis__rz__body(double, %Qubit*)
declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1
attributes #0 = { "entry_point" "num_required_qubits"="2" "num_required_results"="2" "output_labeling_schema" "qir_profiles"="custom" }
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}
The method I used to decode the floats:
import struct
def decode_double(encoding: str) -> float:
try:
return float(encoding)
except ValueError:
n = int(encoding, 16)
return struct.unpack("d", struct.pack("Q", n))[0]
This issue is now fixed, but we should add a test.
I will raise a separate issue for the fact that the simulation appears to be noiseless (i.e. all results are (0,0) or (1,1)), even when noisy_simulation=True
is specified.
Output:
All shots should produce (0, 0) or (1, 1); instead they produce (0, 0) or (1, 0).