Skip to content

Commit

Permalink
Build infrastructure for katas (#160)
Browse files Browse the repository at this point in the history
This change creates the build infrastructure to compose and expose katas.

---------

Co-authored-by: Cesar Zaragoza Cortes <cesarzc@ntdev.microsoft.com>
Co-authored-by: Mine Starks <16928427+minestarks@users.noreply.github.com>
  • Loading branch information
3 people authored Apr 18, 2023
1 parent 627b35b commit 0e349e1
Show file tree
Hide file tree
Showing 31 changed files with 546 additions and 55 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
filename = 'qsc_wasm.d.cts'

shutil.copy2(fullpath, os.path.join(lib_dir, filename))

npm_args = [npm_cmd, 'run', 'build']
result = subprocess.run(npm_args, check=True, text=True, cwd=npm_src)

Expand Down
1 change: 1 addition & 0 deletions compiler/qsc_wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ crate-type = ["rlib", "cdylib"]
qsc_eval = { path = "../qsc_eval"}
qsc_frontend = { path = "../qsc_frontend"}
qsc_passes = { path = "../qsc_passes"}
katas = { path = "../../katas"}
# This is a transitive dependency of qir-stdlib which fails to build for wasm if 'js' feature isn't enabled.
getrandom = { workspace = true, features = ["js"] }
js-sys = { workspace = true }
Expand Down
33 changes: 33 additions & 0 deletions compiler/qsc_wasm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use katas::run_kata;
use num_bigint::BigUint;
use num_complex::Complex64;
use once_cell::sync::OnceCell;
Expand Down Expand Up @@ -371,6 +372,38 @@ pub fn run(
}
}

fn run_kata_exercise_internal<F>(
verification_source: &str,
kata_implementation: &str,
event_cb: F,
) -> Result<bool, Vec<qsc_eval::stateless::Error>>
where
F: Fn(&str),
{
let mut out = CallbackReceiver { event_cb };
run_kata([verification_source, kata_implementation], &mut out)
}

#[wasm_bindgen]
pub fn run_kata_exercise(
verification_source: &str,
kata_implementation: &str,
event_cb: &js_sys::Function,
) -> Result<JsValue, JsValue> {
match run_kata_exercise_internal(verification_source, kata_implementation, |msg: &str| {
let _ = event_cb.call1(&JsValue::null(), &JsValue::from_str(msg));
}) {
Ok(v) => Ok(JsValue::from_bool(v)),
Err(e) => {
// TODO: Handle multiple errors.
let first_error = e
.first()
.expect("Running kata failed but no errors were reported");
Err(JsError::from(first_error).into())
}
}
}

#[cfg(test)]
mod test {
#[test]
Expand Down
49 changes: 49 additions & 0 deletions katas/content/katas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//@ts-check

/**
* Katas Taxonomy
*
* A Kata is a top-level container of educational items (exercises and examples) which are used to explain a particular
* topic.
*
* This file contains the information needed to build the content for all the Katas, and its main purpose is to convey
* ordering. Each Kata and each item within a Kata is listed in the order it is meant to be presented to students.
*
* Each Kata is organized in a directory where a content.md file is present, and multiple sub-directories. Each
* sub-directory represents an item within the Kata and its specific content depends on the type of item it represents.
*/

/**
* @type {Array<
* {
* directory: string,
* items: Array<{
* type: string,
* directory: string
* }>
* }>}
*/
exports.katas = [
{
directory: "single_qubit_gates",
items: [
{
type: "exercise",
directory: "y_gate"
},
{
type: "exercise",
directory: "global_phase_i"
}
]
},
{
directory: "multi_qubit_gates",
items: [
{
type: "exercise",
directory: "preparing_bell_state"
}
]
}
];
9 changes: 9 additions & 0 deletions katas/content/multi_qubit_gates/content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Multi-Qubit Gates

This tutorial continues the introduction to quantum gates, focusing on applying quantum gates to multi-qubit systems.

This tutorial covers the following topics:

- Applying quantum gates to a part of the system
- $\\text{CNOT}$ and $\\text{SWAP}$ gates
- Controlled gates
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Preparing a Bell state

**Input:** Two qubits in state $|00\\rangle$, stored in an array of length 2.

**Goal:** Transform the system into the Bell state $\\Phi^+ = \\frac{1}{\\sqrt{2}}\\big(|00\\rangle + |11\\rangle\\big)$.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Kata {
operation BellState (qs : Qubit[]) : Unit is Adj {
// ...
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Kata {
operation BellState (qs : Qubit[]) : Unit is Adj {
H(qs[0]);
CNOT(qs[0], qs[1]);
}
}
41 changes: 41 additions & 0 deletions katas/content/multi_qubit_gates/preparing_bell_state/verify.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace Kata {
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Intrinsic;

operation BellStateReference (qs : Qubit[]) : Unit is Adj {
body ... {
H(qs[0]);
CNOT(qs[0], qs[1]);
}
adjoint ... {
CNOT(qs[0], qs[1]);
H(qs[0]);
}
}

operation Verify() : Bool {
let task = BellState;
let taskRef = BellStateReference;

use targetRegister = Qubit[2];

task(targetRegister);
Adjoint taskRef(targetRegister);

if CheckAllZero(targetRegister) {
task(targetRegister);
DumpMachine();
return true;
}

ResetAll(targetRegister);

// Use DumpMachine to display actual vs desired state.
task(targetRegister);
DumpMachine();
ResetAll(targetRegister);
taskRef(targetRegister);
DumpMachine();
return false;
}
}
8 changes: 8 additions & 0 deletions katas/content/single_qubit_gates/content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Single-Qubit Gates

This tutorial introduces you to single-qubit gates. Quantum gates are the quantum counterpart to classical logic gates, acting as the building blocks of quantum algorithms. Quantum gates transform qubit states in various ways, and can be applied sequentially to perform complex quantum calculations. Single-qubit gates, as their name implies, act on individual qubits. You can learn more at [Wikipedia](https://en.wikipedia.org/wiki/Quantum_logic_gate).

This tutorial covers the following topics:
* Matrix representation
* Ket-bra representation
* The most important single-qubit gates
5 changes: 5 additions & 0 deletions katas/content/single_qubit_gates/global_phase_i/content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Applying a global phase $i$

**Input:** A qubit in an arbitrary state $|\\psi\\rangle = \\alpha|0\\rangle + \\beta|1\\rangle$.

**Goal:** Use several Pauli gates to change the qubit state to $i|\\psi\\rangle = i\\alpha|0\\rangle + i\\beta|1\\rangle$.
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,13 @@ namespace Kata {
CNOT(aux, target);
H(aux);

if CheckZero(target) {
if CheckZero(aux) {
task(target);
DumpMachine();
return true;
}
if CheckAllZero([aux, target]) {
task(target);
DumpMachine();
return true;
}

Reset(aux);
Reset(target);
ResetAll([aux, target]);

// Use DumpMachine to display actual vs desired state.
task(target);
Expand Down
5 changes: 5 additions & 0 deletions katas/content/single_qubit_gates/y_gate/content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### The $Y$ gate

**Input:** A qubit in an arbitrary state $|\\psi\\rangle = \\alpha|0\\rangle + \\beta|1\\rangle$.

**Goal:** Apply the Y gate to the qubit, i.e., transform the given state into $i\\alpha|1\\rangle - i\\beta|0\\rangle$.
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,13 @@ namespace Kata {
CNOT(aux, target);
H(aux);

if CheckZero(target) {
if CheckZero(aux) {
task(target);
DumpMachine();
return true;
}
if CheckAllZero([aux, target]) {
task(target);
DumpMachine();
return true;
}

Reset(aux);
Reset(target);
ResetAll([aux, target]);

// Use DumpMachine to display actual vs desired state.
task(target);
Expand Down
10 changes: 0 additions & 10 deletions katas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,6 @@ use qsc_eval::val::Value;

const KATA_VERIFY: &str = "Kata.Verify()";

#[must_use]
pub fn verify_kata(
verification_source: &str,
kata_implementation: &str,
recv: &mut impl Receiver,
) -> bool {
let sources = [verification_source, kata_implementation];
run_kata(sources, recv).unwrap_or(false)
}

/// # Errors
/// Returns a vector of errors if compilation or evaluation failed.
///
Expand Down
13 changes: 9 additions & 4 deletions katas/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{
fn katas_qsharp_dir() -> PathBuf {
env::current_dir()
.expect("test should have current directory")
.join("qs")
.join("content")
}

fn run_kata(
Expand All @@ -37,7 +37,7 @@ fn validate_exercise(path: impl AsRef<Path>) {
run_kata([&placeholder, &verify]).expect("placeholder should succeed");
}

fn validate_module(path: impl AsRef<Path>) {
fn validate_kata(path: impl AsRef<Path>) {
for entry in fs::read_dir(path).expect("directory should be readable") {
let path = entry.expect("entry should be usable").path();
if path.is_dir() {
Expand All @@ -47,6 +47,11 @@ fn validate_module(path: impl AsRef<Path>) {
}

#[test]
fn verify_single_qubit_gates_module() {
validate_module(katas_qsharp_dir().join("single_qubit_gates"));
fn validate_single_qubit_gates_kata() {
validate_kata(katas_qsharp_dir().join("single_qubit_gates"));
}

#[test]
fn validate_multi_qubit_gates_kata() {
validate_kata(katas_qsharp_dir().join("multi_qubit_gates"));
}
1 change: 1 addition & 0 deletions npm/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist/
lib/
src/*.generated.*
Loading

0 comments on commit 0e349e1

Please sign in to comment.