Conversation
|
Change in memory usage detected by benchmark. Memory Report for fd2595c
|
|
Change in memory usage detected by benchmark. Memory Report for 6c5e7da
|
swernli
left a comment
There was a problem hiding this comment.
Reviewed code so far, and provided some feedback. Also, it looks like the pipeline is blocked due to some pending merge conflicts.
| } | ||
|
|
||
| /// Asserts that given Q# expression fails to compile with given error message. | ||
| pub fn test_compile_fails(expr: &str, lib: &str, expected_error_substring: &str) { |
There was a problem hiding this comment.
Is this new function necessary? There are other tests that use test_expression_fails defined above and then expect on the output string. Would that be sufficient for new tests?
| logical_counts_expr(&mut interpreter, expr) | ||
| .unwrap_or_else(|errs| panic_with_resource_estimation_errors(&errs)) | ||
| } | ||
|
|
||
| fn panic_with_resource_estimation_errors(errs: &[ResourceEstimatorError]) -> ! { | ||
| let joined = errs | ||
| .iter() | ||
| .map(|e| format!("{e}:{e:?}")) | ||
| .collect::<Vec<_>>() | ||
| .join("\n"); | ||
| panic!("resource estimation failed:\n{joined}"); | ||
| } |
There was a problem hiding this comment.
Rather than have a utility to panic with all the errors joined, you could just use the first error returned. Most of the APIs other than compile use a vector of errors for compatibility sake with parts of the infra but only ever return one error.
| /// Memory register to transform. | ||
| /// ## op | ||
| /// Operation to apply to the temporary compute buffer. | ||
| operation DoComputation(mem_qs : MemoryQubit[], op : Qubit[] => Unit) : Unit { |
There was a problem hiding this comment.
I feel like "do" reads weird here... I think ApplyComputation would better match our naming patterns.
| } | ||
|
|
||
| // MemoryQubit operations. | ||
| operation __quantum__qis__memory_qubit_load(memory_qubit : MemoryQubit, qubit : Qubit) : Unit { |
There was a problem hiding this comment.
To follow QIR naming conventions, things with __qis__ should end in __body, making this one __quantum__qis__memory_qubit_load__body. I think the "qubit" part may be a bit redundant, since we already have "quantum" and "qis" which stands for Quantum Intruction Set, so __quantum__qis__memory_load__body would be fine. Likewise the corresponding operation below would be __quantum__qis__memory_store__body.
Side note: it seems awkward to add __body but it is really only to differentiation between the inverse/adjoint operations, which have the __adj suffix.
| // # Description | ||
| // Prepares a compute qubit in |1>, stores it in a memory qubit, then loads | ||
| // it back and measures. The result should be `One`. | ||
|
|
||
| import Std.MemoryQubits.*; | ||
|
|
||
| operation Main() : Result { | ||
| use (q, mem) = (Qubit(), MemoryQubit()); | ||
|
|
||
| X(q); | ||
| Store(q, mem); | ||
| Load(mem, q); | ||
|
|
||
| return MResetZ(q); | ||
| } |
There was a problem hiding this comment.
I think this sample could use some additional explanatory text in the top level description and comments in the body itself, like our other language samples do. The motivation is both to help educate users and to act as guidance for LLMs, so it's woth explaining the patterns and motivations here.
| "__quantum__qis__mresetz__body" => { | ||
| Ok(self.measure_qubit(builder::mresetz_decl(), args_value)) | ||
| } | ||
| "__quantum__qis__memory_qubit_load" | "__quantum__qis__memory_qubit_load__body" => { |
There was a problem hiding this comment.
Once the name fix in the libraries is added, only the __body name is needed here. Same for the case below.
| @@ -1766,6 +1770,56 @@ impl<'a> PartialEvaluator<'a> { | |||
| "__quantum__qis__mresetz__body" => { | |||
| Ok(self.measure_qubit(builder::mresetz_decl(), args_value)) | |||
| } | |||
There was a problem hiding this comment.
Looks like this file is missing some clippy lint clean up. The two cases for load and store are identical, since the arguments ordering is enough to change the directionality of the operation.
| .try_into() | ||
| .expect("could not convert qubit ID to u32"), | ||
| )), | ||
| Value::MemoryQubit(q) => Operand::Literal(Literal::Qubit( |
There was a problem hiding this comment.
This can be combined with the qubit case above.
| let callable = Callable { | ||
| name: "__quantum__qis__swap__body".to_string(), | ||
| input_type: vec![rir::Ty::Prim(rir::Prim::Qubit), rir::Ty::Prim(rir::Prim::Qubit)], | ||
| output_type: None, | ||
| body: None, | ||
| call_type: CallableType::Regular, | ||
| }; |
There was a problem hiding this comment.
to match the pattern we have above, this should be adder to the builder class instead of inlined here.
| "__quantum__rt__qubit_allocate" | "__quantum__rt__qubit_borrow" => { | ||
| "__quantum__rt__qubit_allocate" | ||
| | "__quantum__rt__qubit_borrow" | ||
| | "__quantum__rt__memory_qubit_allocate" => { |
There was a problem hiding this comment.
no action on this, just a note to confirm understanding: this is consistent with the goal of supporting memory qubit programs as normal compute programs in QIR, as this does not guarantee that the two qubit types will use distinct pools, and if/when we want to support memory qubits as a distinct pool of ids we'd want to differentiate the two kinds of allocation/release calls with separate management (among other changes, like emitting load and store directly). Does that match your expectation as well?
This PR adds support for new Q# type
MemoryQubitand extends standard library with operations on it.A “Memory Qubit” is a useful abstraction in quantum computing. It is a logical qubit on which gates or measurements are not performed directly. It can only hold a quantum state. When we want to do something with that state, we must “load” it to a regular (“compute”) qubit. When we want to retain state of compute qubit for a while but don’t perform computations, we can “store” it to a memory qubit.
This PR contains:
usesyntax (similarly to Qubits) and translate it to allocation instrinsic.memory_qubit_allocate,memory_qubit_load,memory_qubit_store). Together with existingqubit_free, this is the interface between the Q# language and backends.