Skip to content

Commit

Permalink
Expose pauli noise settings in VS Code (#1975)
Browse files Browse the repository at this point in the history
Added VS Code settings for the noise model to use when running
histograms.

---------

Co-authored-by: Dmitry Vasilevsky <dmitryv@microsoft.com>
  • Loading branch information
billti and Dmitry Vasilevsky authored Oct 25, 2024
1 parent a37c324 commit 25aa936
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 12 deletions.
1 change: 1 addition & 0 deletions compiler/qsc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub mod line_column {

pub use qsc_eval::{
backend::{Backend, SparseSim},
noise::PauliNoise,
state::{
fmt_basis_state_label, fmt_complex, format_state_id, get_matrix_latex, get_phase,
get_state_latex,
Expand Down
25 changes: 25 additions & 0 deletions npm/qsharp/src/compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ export interface ICompiler {
eventHandler: IQscEventTarget,
): Promise<void>;

runWithPauliNoise(
program: ProgramConfig,
expr: string,
shots: number,
pauliNoise: number[],
eventHandler: IQscEventTarget,
): Promise<void>;

getQir(program: ProgramConfig): Promise<string>;

getEstimates(program: ProgramConfig, params: string): Promise<string>;
Expand Down Expand Up @@ -171,6 +179,22 @@ export class Compiler implements ICompiler {
);
}

async runWithPauliNoise(
program: ProgramConfig,
expr: string,
shots: number,
pauliNoise: number[],
eventHandler: IQscEventTarget,
): Promise<void> {
this.wasm.runWithPauliNoise(
toWasmProgramConfig(program, "unrestricted"),
expr,
(msg: string) => onCompilerEvent(msg, eventHandler!),
shots!,
pauliNoise,
);
}

async getQir(program: ProgramConfig): Promise<string> {
return this.wasm.get_qir(toWasmProgramConfig(program, "base"));
}
Expand Down Expand Up @@ -299,6 +323,7 @@ export const compilerProtocol: ServiceProtocol<ICompiler, QscEventData> = {
getCircuit: "request",
getDocumentation: "request",
run: "requestWithProgress",
runWithPauliNoise: "requestWithProgress",
checkExerciseSolution: "requestWithProgress",
},
eventNames: ["DumpMachine", "Matrix", "Message", "Result"],
Expand Down
28 changes: 28 additions & 0 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,34 @@
"The Adaptive_RI target profile includes all of the required Adaptive Profile capabilities, as well as the optional integer computation and qubit reset capabilities, as defined by the QIR specification."
],
"markdownDescription": "Setting the target profile allows the Q# extension to generate programs that are compatible with a specific target. The target is the hardware or simulator which will be used to run the Q# program. [Learn more](https://aka.ms/qdk.qir)"
},
"Q#.simulation.pauliNoise": {
"markdownDescription": "The Pauli noise to apply when running multiple shots via the Histogram command. This is applied for every gate or measurement on all qubits referenced.\n\nProbability values are in the range [0, 1].",
"type": "object",
"additionalProperties": false,
"properties": {
"X": {
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 1,
"description": "The probability of a bit flip error occurring"
},
"Y": {
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 1,
"description": "The probability of a bit-and-phase flip error occurring"
},
"Z": {
"type": "number",
"default": 0,
"minimum": 0,
"maximum": 1,
"description": "The probability of a phase flip error occurring"
}
}
}
}
},
Expand Down
12 changes: 12 additions & 0 deletions vscode/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,15 @@ export function getTargetFriendlyName(targetProfile?: string) {
return "Q#: invalid";
}
}

export function getPauliNoiseModel(): number[] {
const pauliNoiseSettings = vscode.workspace.getConfiguration(
"Q#.simulation.pauliNoise",
);
const noiseTuple = [
pauliNoiseSettings.get("X", 0),
pauliNoiseSettings.get("Y", 0),
pauliNoiseSettings.get("Z", 0),
];
return noiseTuple;
}
23 changes: 16 additions & 7 deletions vscode/src/webview/webview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,22 @@ function App({ state }: { state: State }) {
return <div>Loading...</div>;
case "histogram":
return (
<Histogram
data={new Map(state.buckets)}
shotCount={state.shotCount}
filter=""
onFilter={onFilter}
shotsHeader={true}
></Histogram>
<>
<Histogram
data={new Map(state.buckets)}
shotCount={state.shotCount}
filter=""
onFilter={onFilter}
shotsHeader={true}
></Histogram>
<p style="margin-top: 8px; font-size: 0.8em">
Note: If a{" "}
<a href="vscode://settings/Q%23.simulation.pauliNoise">
noise model
</a>{" "}
has been configured, this may impact results
</p>
</>
);
case "estimates":
return (
Expand Down
5 changes: 4 additions & 1 deletion vscode/src/webviewPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { showDocumentationCommand } from "./documentation";
import { getActiveProgram } from "./programConfig";
import { EventType, sendTelemetryEvent } from "./telemetry";
import { getRandomGuid } from "./utils";
import { getPauliNoiseModel } from "./config";

const QSharpWebViewType = "qsharp-webview";
const compilerRunTimeoutMs = 1000 * 60 * 5; // 5 minutes
Expand Down Expand Up @@ -343,10 +344,12 @@ export function registerWebViewCommands(context: ExtensionContext) {
const start = performance.now();
sendTelemetryEvent(EventType.HistogramStart, { associationId }, {});

await worker.run(
const noise = getPauliNoiseModel();
await worker.runWithPauliNoise(
program.programConfig,
"",
parseInt(numberOfShots),
noise,
evtTarget,
);
sendTelemetryEvent(
Expand Down
48 changes: 45 additions & 3 deletions wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use qsc::{
CircuitEntryPoint,
},
target::Profile,
LanguageFeatures, PackageStore, PackageType, SourceContents, SourceMap, SourceName, SparseSim,
TargetCapabilityFlags,
LanguageFeatures, PackageStore, PackageType, PauliNoise, SourceContents, SourceMap, SourceName,
SparseSim, TargetCapabilityFlags,
};
use resource_estimator::{self as re, estimate_entry};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -314,6 +314,8 @@ where
Ok(())
}
}

#[allow(clippy::too_many_arguments)]
fn run_internal_with_features<F>(
sources: SourceMap,
event_cb: F,
Expand All @@ -322,6 +324,7 @@ fn run_internal_with_features<F>(
capabilities: TargetCapabilityFlags,
store: PackageStore,
dependencies: &Dependencies,
pauliNoise: &PauliNoise,
) -> Result<(), Box<interpret::Error>>
where
F: FnMut(&str),
Expand Down Expand Up @@ -355,7 +358,8 @@ where
};

for _ in 0..shots {
let result = interpreter.eval_entry_with_sim(&mut SparseSim::new(), &mut out);
let result =
interpreter.eval_entry_with_sim(&mut SparseSim::new_with_noise(pauliNoise), &mut out);
let mut success = true;
let msg: serde_json::Value = match result {
Ok(value) => serde_json::Value::String(value.to_string()),
Expand All @@ -379,6 +383,17 @@ pub fn run(
expr: &str,
event_cb: &js_sys::Function,
shots: u32,
) -> Result<bool, JsValue> {
runWithPauliNoise(program, expr, event_cb, shots, &JsValue::null())
}

#[wasm_bindgen]
pub fn runWithPauliNoise(
program: ProgramConfig,
expr: &str,
event_cb: &js_sys::Function,
shots: u32,
pauliNoise: &JsValue,
) -> Result<bool, JsValue> {
let (source_map, capabilities, language_features, store, deps) =
into_qsc_args(program, Some(expr.into())).map_err(|mut e| {
Expand All @@ -397,6 +412,32 @@ pub fn run(
// See example at https://rustwasm.github.io/wasm-bindgen/reference/receiving-js-closures-in-rust.html
let _ = event_cb.call1(&JsValue::null(), &JsValue::from(msg));
};

// See if the pauliNoise JsValue is an array
let noise = if pauliNoise.is_array() {
let pauliArray = js_sys::Array::from(pauliNoise);
if pauliArray.length() != 3 {
return Err(JsError::new("Pauli noise must have 3 probabilities").into());
}
PauliNoise::from_probabilities(
pauliArray
.get(0)
.as_f64()
.expect("Probabilities should be floats"),
pauliArray
.get(1)
.as_f64()
.expect("Probabilities should be floats"),
pauliArray
.get(2)
.as_f64()
.expect("Probabilities should be floats"),
)
.expect("Unable to create Pauli noise from the array provided")
} else {
PauliNoise::default()
};

match run_internal_with_features(
source_map,
event_cb,
Expand All @@ -405,6 +446,7 @@ pub fn run(
capabilities,
store,
&deps[..],
&noise,
) {
Ok(()) => Ok(true),
Err(e) => Err(JsError::from(e).into()),
Expand Down
5 changes: 4 additions & 1 deletion wasm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

use expect_test::expect;
use indoc::indoc;
use qsc::{interpret, LanguageFeatures, PackageStore, SourceMap, TargetCapabilityFlags};
use qsc::{
interpret, LanguageFeatures, PackageStore, PauliNoise, SourceMap, TargetCapabilityFlags,
};

use crate::_get_qir;

Expand All @@ -22,6 +24,7 @@ where
TargetCapabilityFlags::all(),
store,
&[(std_id, None)],
&PauliNoise::default(),
)
}

Expand Down

0 comments on commit 25aa936

Please sign in to comment.