1 Commits

Author SHA1 Message Date
df91fd9f96 Incomplete port 2025-10-02 07:56:09 -07:00
29 changed files with 1920 additions and 463 deletions

View File

@@ -26,7 +26,7 @@ jobs:
- name: "Download Typstyle" - name: "Download Typstyle"
run: | run: |
wget -q "https://github.com/Enter-tainer/typstyle/releases/download/v0.13.17/typstyle-x86_64-unknown-linux-musl" wget -q "https://github.com/Enter-tainer/typstyle/releases/download/v0.12.14/typstyle-x86_64-unknown-linux-musl"
chmod +x typstyle-x86_64-unknown-linux-musl chmod +x typstyle-x86_64-unknown-linux-musl
- name: Check typst formatting - name: Check typst formatting
@@ -62,7 +62,7 @@ jobs:
# more control anyway. # more control anyway.
- name: "Download Typst" - name: "Download Typst"
run: | run: |
wget -q "https://github.com/typst/typst/releases/download/v0.13.1/typst-x86_64-unknown-linux-musl.tar.xz" wget -q "https://github.com/typst/typst/releases/download/v0.12.0/typst-x86_64-unknown-linux-musl.tar.xz"
tar -xf "typst-x86_64-unknown-linux-musl.tar.xz" tar -xf "typst-x86_64-unknown-linux-musl.tar.xz"
mv "typst-x86_64-unknown-linux-musl/typst" . mv "typst-x86_64-unknown-linux-musl/typst" .
rm "typst-x86_64-unknown-linux-musl.tar.xz" rm "typst-x86_64-unknown-linux-musl.tar.xz"

View File

@@ -3,10 +3,13 @@
// Re-exports // Re-exports
// All functions that maybe used by client code are listed here // All functions that maybe used by client code are listed here
#import "misc.typ": * #import "misc.typ": *
#import "object.typ": definition, example, generic, problem, remark, theorem #import "object.typ": problem, definition, theorem, example, remark, generic
#import "solution.typ": ( #import "solution.typ": (
if_no_solutions, if_solutions, if_solutions_else, instructornote, if_solutions,
sample_solution, solution, if_no_solutions,
if_solutions_else,
solution,
instructornote,
) )
@@ -35,7 +38,10 @@
margin: 20mm, margin: 20mm,
width: 8.5in, width: 8.5in,
height: 11in, height: 11in,
footer: align(center, context counter(page).display()), footer: align(
center,
context counter(page).display(),
),
footer-descent: 5mm, footer-descent: 5mm,
) )
@@ -96,8 +102,8 @@
// Make handout title // Make handout title
{ {
import "header.typ": make_header, short_solution_warning, solution_warning import "header.typ": make_header, solution_warning, short_solution_warning
import "solution.typ": reset_solutions, solutions_state import "solution.typ": solutions_state, reset_solutions
reset_solutions() reset_solutions()

View File

@@ -29,7 +29,11 @@
} }
// Render the object // Render the object
block(above: 8mm, below: 2mm, text(weight: "bold", obj_content)) block(
above: 8mm,
below: 2mm,
text(weight: "bold", obj_content),
)
// Generate labeled metadata for this object. // Generate labeled metadata for this object.
// //
@@ -53,7 +57,7 @@
if not ( if not (
it.element != none it.element != none
and it.element.has("value") and it.element.has("value")
and type(it.element.value) == dictionary and type(it.element.value) == "dictionary"
and it.element.value.keys().contains(magic_key) and it.element.value.keys().contains(magic_key)
) { ) {
// This label is not attached to object metadata // This label is not attached to object metadata
@@ -96,5 +100,9 @@
#let remark = _mkobj("Remark") #let remark = _mkobj("Remark")
#let generic(obj_content) = { #let generic(obj_content) = {
block(above: 8mm, below: 2mm, text(weight: "bold", obj_content)) block(
above: 8mm,
below: 2mm,
text(weight: "bold", obj_content),
)
} }

View File

@@ -1,4 +1,4 @@
#import "misc.typ": oblue, ored #import "misc.typ": ored, oblue
/// If false, hide instructor info. /// If false, hide instructor info.
@@ -61,71 +61,57 @@
} }
#let solution(content) = { #let solution(content) = {
if_solutions(align(center, stack( if_solutions(
block( align(
width: 100%, center,
breakable: false, stack(
fill: ored, block(
stroke: ored + 2pt, width: 100%,
inset: 1.5mm, breakable: false,
align(left, text(fill: white, weight: "bold", [Solution:])), fill: ored,
), stroke: ored + 2pt,
inset: 1.5mm,
align(left, text(fill: white, weight: "bold", [Solution:])),
),
block( block(
width: 100%, width: 100%,
height: auto, height: auto,
breakable: false, breakable: false,
fill: ored.lighten(80%).desaturate(10%), fill: ored.lighten(80%).desaturate(10%),
stroke: ored + 2pt, stroke: ored + 2pt,
inset: 3mm, inset: 3mm,
align(left, content), align(left, content),
),
),
), ),
))) )
} }
#let sample_solution(content) = {
align(center, stack(
block(
width: 100%,
breakable: false,
fill: oblue,
stroke: oblue + 2pt,
inset: 1.5mm,
align(left, text(fill: white, weight: "bold", [Sample Solution:])),
),
block(
width: 100%,
height: auto,
breakable: false,
fill: oblue.lighten(80%).desaturate(10%),
stroke: oblue + 2pt,
inset: 3mm,
align(left, content),
),
))
}
#let instructornote(content) = { #let instructornote(content) = {
if_solutions(align(center, stack( if_solutions(
block( align(
width: 100%, center,
breakable: false, stack(
fill: oblue, block(
stroke: oblue + 2pt, width: 100%,
inset: 1.5mm, breakable: false,
align(left, text(fill: white, weight: "bold", [Instructor note:])), fill: oblue,
), stroke: oblue + 2pt,
inset: 1.5mm,
align(left, text(fill: white, weight: "bold", [Instructor note:])),
),
block( block(
width: 100%, width: 100%,
height: auto, height: auto,
breakable: false, breakable: false,
fill: oblue.lighten(80%).desaturate(10%), fill: oblue.lighten(80%).desaturate(10%),
stroke: oblue + 2pt, stroke: oblue + 2pt,
inset: 3mm, inset: 3mm,
align(left, content), align(left, content),
),
),
), ),
))) )
} }

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
= Floats = Floats
#definition() #definition()
@@ -33,66 +33,72 @@ Another way we can interpret a bit string is as a _signed floating-point decimal
Floats represent a subset of the real numbers, and are interpreted as follows: \ Floats represent a subset of the real numbers, and are interpreted as follows: \
#note([The following only applies to floats that consist of 32 bits. We won't encounter any others today.]) #note([The following only applies to floats that consist of 32 bits. We won't encounter any others today.])
#align(center, box(inset: 2mm, cetz.canvas({ #align(
import cetz.draw: * center,
box(
inset: 2mm,
cetz.canvas({
import cetz.draw: *
let chars = ( let chars = (
`0`, `0`,
`b`, `b`,
`0`, `0`,
`_`, `_`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`_`, `_`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`_`, `_`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`_`, `_`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
`0`, `0`,
) )
let x = 0 let x = 0
for c in chars { for c in chars {
content((x, 0), c) content((x, 0), c)
x += 0.25 x += 0.25
} }
let y = -0.4 let y = -0.4
line((0.3, y), (0.65, y)) line((0.3, y), (0.65, y))
content((0.45, y - 0.2), [s]) content((0.45, y - 0.2), [s])
line((0.85, y), (2.9, y)) line((0.85, y), (2.9, y))
content((1.9, y - 0.2), [exponent]) content((1.9, y - 0.2), [exponent])
line((3.10, y), (9.4, y)) line((3.10, y), (9.4, y))
content((6.3, y - 0.2), [fraction]) content((6.3, y - 0.2), [fraction])
}))) }),
),
)
- The first bit denotes the sign of the float's value - The first bit denotes the sign of the float's value
We'll label it $s$. \ We'll label it $s$. \

View File

@@ -1,6 +1,6 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#import "@preview/cetz-plot:0.1.2": chart, plot #import "@preview/cetz-plot:0.1.0": plot, chart
= Integers and Floats = Integers and Floats
@@ -44,11 +44,19 @@ This allows us to improve the average error of our linear approximation:
{ {
let domain = (0, 1) let domain = (0, 1)
plot.add(f1, domain: domain, label: $log(1+x)$, style: ( plot.add(
stroke: ogrape, f1,
)) domain: domain,
label: $log(1+x)$,
style: (stroke: ogrape),
)
plot.add(f2, domain: domain, label: $x$, style: (stroke: oblue)) plot.add(
f2,
domain: domain,
label: $x$,
style: (stroke: oblue),
)
}, },
) )
}) })
@@ -82,11 +90,19 @@ This allows us to improve the average error of our linear approximation:
{ {
let domain = (0, 1) let domain = (0, 1)
plot.add(f1, domain: domain, label: $log(1+x)$, style: ( plot.add(
stroke: ogrape, f1,
)) domain: domain,
label: $log(1+x)$,
style: (stroke: ogrape),
)
plot.add(f2, domain: domain, label: $x$, style: (stroke: oblue)) plot.add(
f2,
domain: domain,
label: $x$,
style: (stroke: oblue),
)
}, },
) )
}) })
@@ -104,13 +120,16 @@ We won't bother with this---we'll simply leave the correction term as an opaque
#v(1fr) #v(1fr)
#note(type: "Note", [ #note(
"Average error" above is simply the area of the region between the two graphs: type: "Note",
$ [
integral_0^1 abs(#v(1mm) log(1+x)_2 - (x+epsilon) #v(1mm)) "Average error" above is simply the area of the region between the two graphs:
$ $
Feel free to ignore this note, it isn't a critical part of this handout. integral_0^1 abs( #v(1mm) log(1+x)_2 - (x+epsilon) #v(1mm))
]) $
Feel free to ignore this note, it isn't a critical part of this handout.
],
)
#pagebreak() #pagebreak()
@@ -130,11 +149,12 @@ $
Let $E$ and $F$ be the exponent and float bits of $x_f$. \ Let $E$ and $F$ be the exponent and float bits of $x_f$. \
We then have: We then have:
$ $
log_2(x_f) & = log_2 ( 2^(E-127) times (1 + (F) / (2^23)) ) \ log_2(x_f)
& = E - 127 + log_2(1 + F / (2^23)) \ &= log_2 ( 2^(E-127) times (1 + (F) / (2^23)) ) \
& approx E-127 + F / (2^23) + epsilon \ &= E - 127 + log_2(1 + F / (2^23)) \
& = 1 / (2^23)(2^23 E + F) - 127 + epsilon \ & approx E-127 + F / (2^23) + epsilon \
& = 1 / (2^23)(x_i) - 127 + epsilon &= 1 / (2^23)(2^23 E + F) - 127 + epsilon \
&= 1 / (2^23)(x_i) - 127 + epsilon
$ $
]) ])

View File

@@ -0,0 +1,35 @@
#import "@local/handout:0.1.0": *
#show: handout.with(
title: [Intro to Quantum Computing],
by: "Mark",
)
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
#include "src/parts/01 bits.typ"
#pagebreak()
#include "src/parts/02 qubit.typ"
#pagebreak()
#include "src/parts/03 two qubits.typ"
#pagebreak()
// DONE UNTIL HERE
#include "src/parts/04 logic gates.typ"
#pagebreak()
#include "src/parts/05 quantum gates.typ"
#pagebreak()
#include "src/parts/06 hxh.typ"
#pagebreak()
#include "src/parts/07 superdense.typ"
#pagebreak()
#include "src/parts/08 teleport.typ"

View File

@@ -0,0 +1,349 @@
#import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2"
= Probabilistic Bits
#definition()
As we already know, a _classical bit_ may take the values `0` and `1`.
We can model this with a two-sided coin, one face of which is labeled `0`, and the other, `1`.
#v(2mm)
Of course, if we toss such a "bit-coin," we'll get either `0` or `1`.
We'll denote the probability of getting `0` as $p_0$, and the probability of getting `1` as $p_1$.
As with all probabilities, $p_0 + p_1$ must be equal to 1.
#v(1fr)
#definition()
Say we toss a "bit-coin" and don't observe the result. We now have a _probabilistic bit_, with a probability $p_0$ of being `0`, and a probability $p_1$ of being `1`.
#v(2mm)
We'll represent this probabilistic bit's _state_ as a vector: $mat(p_0; p_1)$
We do *not* assume this coin is fair, and thus $p_0$ might not equal $p_1$.
#note[This may seem a bit redundant: since $p_0 + p_1 = 1$, we can always calculate one probability given the other. We'll still include both probabilities in the state vector, since this provides a clearer analogy to quantum bits.]
#v(1fr)
#definition()
The simplest probabilistic bit states are of course $[0]$ and $[1]$, defined as follows:
- $[0] = mat(1; 0)$
- $[1] = mat(0; 1)$
That is, $[0]$ represents a bit that we known to be `0`, and $[1]$ represents a bit we know to be `1`.
#v(1fr)
#definition()
$[0]$ and $[1]$ form a _basis_ for all possible probabilistic bit states:
Every other probabilistic bit can be written as a _linear combination_ of $[0]$ and $[1]$:
$ mat(p_0; p_1) = p_0 mat(1; 0) + p_1 mat(0; 1) = p_0 [0] + p_1 [1] $
#v(1fr)
#pagebreak()
#problem()
Every possible state of a probabilistic bit is a two-dimensional vector.
Draw all possible states on the axis below.
#table(
columns: (1fr,),
align: center,
stroke: none,
align(center, cetz.canvas({
import cetz.draw: *
set-style(content: (frame: "rect", stroke: none, fill: none, padding: .25))
scale(200%)
line(
(0, 1.5),
(0, 0),
(1.5, 0),
stroke: black + 0.25mm,
)
mark((0, 1.5), (0, 2), symbol: ")>", fill: black)
mark((1.5, 0), (2, 0), symbol: ")>", fill: black)
content((0, 1.5), $p_1$, anchor: "south")
content((1.5, 0), $p_0$, anchor: "west")
circle((0, 0), radius: 0.6mm, fill: black, name: "00")
content("00.south", $mat(0; 0)$, anchor: "north")
circle((0, 1), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.west", $[1]$, anchor: "east")
circle((1, 0), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.south", $[0]$, anchor: "north")
})),
)
#solution[
#table(
columns: (1fr,),
align: center,
stroke: none,
align(center, cetz.canvas({
import cetz.draw: *
set-style(content: (
frame: "rect",
stroke: none,
fill: none,
padding: .25,
))
scale(200%)
line(
(0, 1.5),
(0, 0),
(1.5, 0),
stroke: black + 0.25mm,
)
mark((0, 1.5), (0, 2), symbol: ")>", fill: black)
mark((1.5, 0), (2, 0), symbol: ")>", fill: black)
content((0, 1.5), $p_1$, anchor: "south")
content((1.5, 0), $p_0$, anchor: "west")
line(
(1, 0),
(0, 1),
stroke: ored + 1mm,
)
circle((0, 0), radius: 0.6mm, fill: black, name: "00")
content("00.south", $mat(0; 0)$, anchor: "north")
circle((0, 1), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.west", $[1]$, anchor: "east")
circle((1, 0), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.south", $[0]$, anchor: "north")
})),
)
]
#v(1fr)
#pagebreak()
= Measuring Probabilistic Bits
#definition()
As we noted before, a probabilistic bit represents a coin we've tossed but haven't looked at.
We do not know whether the bit is `0` or `1`, but we do know the probability of both of these outcomes.
#v(2mm)
If we _measure_ (or _observe_) a probabilistic bit, we see either `0` or `1`—and thus our knowledge of its state is updated to either $[0]$ or $[1]$, since we now certainly know what face the coin landed on.
#v(2mm)
Since measurement changes what we know about a probabilistic bit, it changes the probabilistic bit's state. When we measure a bit, its state _collapses_ to either $[0]$ or $[1]$, and the original state of the bit vanishes. We _cannot_ recover the state $[x_0, x_1]$ from a measured probabilistic bit.
#definition("Multiple bits")
Say we have two probabilistic bits, $x$ and $y$, with states $[x] = [x_0, x_1]$ and $[y] = [y_0, y_1]$
#v(2mm)
The _compound state_ of $[x]$ and $[y]$ is exactly what it sounds like: It is the probabilistic two-bit state $|x y angle.r$, where the probabilities of the first bit are determined by $[x]$, and the probabilities of the second are determined by $[y]$.
#problem(label: "firstcompoundstate")
Say $[x] = [2/3, 1/3]$ and $[y] = [3/4, 1/4]$.
- If we measure $x$ and $y$ simultaneously, what is the probability of getting each of `00`, `01`, `10`, and `11`?
- If we measure $y$ first and observe `1`, what is the probability of getting each of `00`, `01`, `10`, and `11`?
#note[*Note:* $[x]$ and $[y]$ are column vectors, but I've written them horizontally to save space.]
#v(1fr)
#problem()
Say $[x] = [2/3, 1/3]$ and $[y] = [3/4, 1/4]$.
What is the probability that $x$ and $y$ produce different outcomes?
#v(1fr)
#pagebreak()
= Tensor Products
#definition("Tensor Products")
The _tensor product_ of two vectors is defined as follows:
$
mat(x_1; x_2) times.circle mat(y_1; y_2) = mat(x_1 mat(y_1; y_2); x_2 mat(y_1; y_2)) = mat(x_1 y_1; x_1 y_2; x_2 y_1; x_2 y_2)
$
That is, we take our first vector, multiply the second vector by each of its components, and stack the result. You could think of this as a generalization of scalar multiplication, where scalar multiplication is a tensor product with a vector in $RR^1$:
$
a mat(x_1; x_2) = mat(a_1) times.circle mat(y_1; y_2) = mat(a_1 mat(y_1; y_2)) = mat(a_1 y_1; a_1 y_2)
$
#problem()
Say $x in RR^n$ and $y in RR^m$.
What is the dimension of $x times.circle y$?
#v(1fr)
#problem(label: "basistp")
What is the following pairwise tensor product?
#v(4mm)
$
{mat(1; 0; 0), mat(0; 1; 0), mat(0; 0; 1)}
times.circle
{mat(1; 0), mat(0; 1)}
$
#v(4mm)
#hint[Distribute the tensor product between every pair of vectors.]
#v(1fr)
#problem()
What is the _span_ of the vectors we found in @basistp?
In other words, what is the set of vectors that can be written as linear combinations of the vectors above?
#v(1fr)
#pagebreak()
#problem()
Say $[x] = [2/3, 1/3]$ and $[y] = [3/4, 1/4]$.
What is $[x] times.circle [y]$? How does this relate to @firstcompoundstate?
#v(1fr)
#problem()
The compound state of two vector-form bits is their tensor product.
Compute the following. Is the result what we'd expect?
- $[0] times.circle [0]$
- $[0] times.circle [1]$
- $[1] times.circle [0]$
- $[1] times.circle [1]$
#hint[Remember that $[0] = mat(1; 0)$ and $[1] = mat(0; 1)$.]
#v(1fr)
#problem(label: "fivequant")
Writing $[0] times.circle [1]$ is a bit tedious. We'll shorten this notation to $[01]$.
In fact, we could go further: if we wanted to write the set of bits $[1] times.circle [1] times.circle [0] times.circle [1]$, \
we could write $[1101]$—but a shorter alternative is $[13]$, since $13$ is `1101` in binary.
#v(2mm)
Write $[5]$ as a three-bit probabilistic state.
#solution[
$[5] = [101] = [1] times.circle [0] times.circle [1] = [0,0,0,0,0,1,0,0]^T$ \
Notice how we're counting from the top, with $[000] = [1,0,...,0]$ and $[111] = [0, ..., 0, 1]$.
]
#v(1fr)
#problem()
Write the three-bit states $[0]$ through $[7]$ as column vectors.
#hint[You do not need to compute every tensor product. Do a few and find the pattern.]
#v(1fr)
#pagebreak()
= Operations on Probabilistic Bits
Now that we can write probabilistic bits as vectors, we can represent operations on these bits with linear transformations—in other words, as matrices.
#definition()
Consider the NOT gate, which operates as follows:
- $"NOT"[0] = [1]$
- $"NOT"[1] = [0]$
What should NOT do to a probabilistic bit $[x_0, x_1]$?
If we return to our coin analogy, we can think of the NOT operation as flipping a coin we have already tossed, without looking at its state. Thus,
$ "NOT" mat(x_0; x_1) = mat(x_1; x_0) $
#review_box("Review: Multiplying vectors by matrices")[
#v(2mm)
$
A v = mat(1, 2; 3, 4) mat(v_0; v_1) = mat(1 v_0 + 2 v_1; 3 v_0 + 4 v_1)
$
#v(2mm)
Note that each element of $A v$ is the dot product of a row in $A$ and a column in $v$.
]
#problem()
Compute the following product:
$ mat(1, 0.5; 0, 1) mat(3; 2) $
#v(1fr)
#remark()
Also, recall that every matrix is linear map, and that every linear map may be written as a matrix. We often use the terms _matrix_, _transformation_, and _linear map_ interchangeably.
#pagebreak()
#problem()
Find the matrix that represents the NOT operation on one probabilistic bit.
#solution[
$
mat(0, 1; 1, 0)
$
]
#v(1fr)
#problem("Extension by linearity")
Say we have an arbitrary operation $M$.
If we know how $M$ acts on $[1]$ and $[0]$, can we compute $M[x]$ for an arbitrary state $[x]$?
Say $[x] = [x_0, x_1]$.
- What is the probability we observe $0$ when we measure $x$?
- What is the probability that we observe $M[0]$ when we measure $M x$?
#v(1fr)
#problem(label: "linearextension")
Write $M[x_0, x_1]$ in terms of $M[0]$, $M[1]$, $x_0$, and $x_1$.
#solution[
$
M mat(x_0; x_1) = x_0 M mat(1; 0) + x_1 M mat(0; 1) = x_0 M[0] + x_1 M[1]
$
]
#v(1fr)
#remark() Every matrix represents a _linear_ map, so the following is always true:
$ A times (p x + q y) = p A x + q A y $
@linearextension is just a special case of this fact.

View File

@@ -0,0 +1,514 @@
#import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2"
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
= One Qubit
Quantum bits (or _qubits_) are very similar to probabilistic bits, but have one major difference: probabilities are replaced with _amplitudes_.
#v(2mm)
Of course, a qubit can take the values `0` and `1`, which are denoted $#ket("0")$ and $#ket("1")$.
Like probabilistic bits, a quantum bit is written as a linear combination of $#ket("0")$ and $#ket("1")$:
$ #ket([$psi$]) = psi_0 #ket("0") + psi_1 #ket("1") $
Such linear combinations are called _superpositions_.
#v(2mm)
The $#ket("")$ you see in the expressions above is called a "ket," and denotes a column vector.
$#ket("0")$ is pronounced "ket zero," and $#ket("1")$ is pronounced "ket one." This is called bra-ket notation.
#note[*Note:* $#bra("0")$ is called a "bra," but we won't worry about that for now.]
#v(2mm)
This is very similar to the "box" $[#h(1.5mm)]$ notation we used for probabilistic bits.
As before, we will write $#ket("0") = mat(1; 0)$ and $#ket("1") = mat(0; 1)$.
#v(8mm)
Recall that probabilistic bits are subject to the restriction that $p_0 + p_1 = 1$.
Quantum bits have a similar condition: $psi_0^2 + psi_1^2 = 1$.
Note that this implies that $psi_0$ and $psi_1$ are both in $[-1, 1]$.
Quantum amplitudes may be negative, but probabilistic bit probabilities cannot.
#v(2mm)
If we plot the set of valid quantum states on our plane, we get a unit circle centered at the origin:
#table(
columns: (1fr,),
align: center,
stroke: none,
align(center, cetz.canvas({
import cetz.draw: *
set-style(content: (frame: "rect", stroke: none, fill: none, padding: .25))
scale(150%)
line(
(0, 1.5),
(0, 0),
(1.5, 0),
stroke: black + 0.25mm,
)
mark((0, 1.5), (0, 2), symbol: ")>", fill: black)
mark((1.5, 0), (2, 0), symbol: ")>", fill: black)
circle((0, 0), radius: 1, stroke: (
paint: black,
thickness: 0.25mm,
dash: "dashed",
))
content((0, 1.5), $p_1$, anchor: "south")
content((1.5, 0), $p_0$, anchor: "west")
circle((0, 1), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.west", $#ket("1")$, anchor: "east")
circle((1, 0), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.south", $#ket("0")$, anchor: "north")
circle((0.87, 0.5), radius: 0.6mm, fill: ored, stroke: ored, name: "00")
content("00.east", $#ket(math.psi)$, anchor: "west")
})),
)
Recall that the set of probabilistic bits forms a line instead:
#table(
columns: (1fr,),
align: center,
stroke: none,
align(center, cetz.canvas({
import cetz.draw: *
set-style(content: (frame: "rect", stroke: none, fill: none, padding: .25))
scale(150%)
line(
(0, 1.5),
(0, 0),
(1.5, 0),
stroke: black + 0.25mm,
)
mark((0, 1.5), (0, 2), symbol: ")>", fill: black)
mark((1.5, 0), (2, 0), symbol: ")>", fill: black)
line(
(1, 0),
(0, 1),
stroke: ored + 1mm,
)
content((0, 1.5), $p_1$, anchor: "south")
content((1.5, 0), $p_0$, anchor: "west")
circle((0, 0), radius: 0.6mm, fill: black, name: "00")
content("00.south", $mat(0; 0)$, anchor: "north")
circle((0, 1), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.west", $[1]$, anchor: "east")
circle((1, 0), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.south", $[0]$, anchor: "north")
})),
)
#problem()
In the above unit circle, the counterclockwise angle from $#ket("0")$ to $#ket([$psi$])$ is $30°$.
Write $#ket([$psi$])$ as a linear combination of $#ket("0")$ and $#ket("1")$.
#v(1fr)
#pagebreak()
#definition("Measurement I")
Just like a probabilistic bit, we must observed $#ket("0")$ or $#ket("1")$ when we measure a qubit.
If we were to measure $#ket([$psi$]) = psi_0 #ket("0") + psi_1 #ket("1")$, we'd observe either $#ket("0")$ or $#ket("1")$, with the following probabilities:
- $cal(P)(#ket("1")) = psi_1^2$
- $cal(P)(#ket("0")) = psi_0^2$
#note[Note that $cal(P)(#ket("0")) + cal(P)(#ket("1")) = 1$.]
#v(2mm)
As before, $#ket([$psi$])$ _collapses_ when it is measured: its state becomes that which we observed in our measurement, leaving no trace of the previous superposition.
#problem()
- What is the probability we observe $#ket("0")$ when we measure $#ket([$psi$])$?
- What can we observe if we measure $#ket([$psi$])$ a second time?
- What are these probabilities for $#ket([$phi$])$?
#table(
columns: (1fr,),
align: center,
stroke: none,
align(center, cetz.canvas({
import cetz.draw: *
set-style(content: (frame: "rect", stroke: none, fill: none, padding: .25))
scale(200%)
line(
(0, 1.5),
(0, 0),
(1.5, 0),
stroke: black + 0.25mm,
)
mark((0, 1.5), (0, 2), symbol: ")>", fill: black)
mark((1.5, 0), (2, 0), symbol: ")>", fill: black)
circle((0, 0), radius: 1, stroke: (
paint: black,
thickness: 0.25mm,
dash: "dashed",
))
content((0, 1.5), $p_1$, anchor: "south")
content((1.5, 0), $p_0$, anchor: "west")
circle((0, 1), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.west", $#ket("1")$, anchor: "east")
circle((1, 0), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.south", $#ket("0")$, anchor: "north")
circle((0.87, 0.5), radius: 0.6mm, fill: ored, stroke: ored, name: "00")
content("00.east", $#ket(math.psi)$, anchor: "west")
arc(
(0, 0),
start: 0deg,
stop: -135deg,
anchor: "origin",
radius: 0.3,
name: "a135",
stroke: gray,
)
mark(
"a135.end",
135deg,
symbol: ")>",
fill: gray,
stroke: gray,
)
content("a135.center", text(fill: gray)[$135degree$], anchor: "north")
line((0, 0), (-0.607, -0.607), stroke: (
paint: gray,
thickness: 0.4mm,
dash: "dotted",
))
mark(
(-0.627, -0.627),
(-0.708, -0.708),
symbol: ")>",
fill: gray,
stroke: gray,
)
arc(
(0, 0),
start: 0deg,
stop: 30deg,
anchor: "origin",
radius: 0.6,
name: "a30",
stroke: gray,
)
mark(
"a30.end",
120deg,
symbol: ")>",
fill: gray,
stroke: gray,
)
content("a30.end", text(fill: gray)[$30degree$], anchor: "south")
line((0, 0), (0.87, 0.5), stroke: (
paint: gray,
thickness: 0.4mm,
dash: "dotted",
))
mark(
(0.80, 0.46),
(0.87, 0.5),
symbol: ")>",
fill: gray,
stroke: gray,
)
circle(
(-0.707, -0.707),
radius: 0.6mm,
fill: ored,
stroke: ored,
name: "00",
)
content("00.west", $#ket(math.phi)$, anchor: "east")
})),
)
#v(1fr)
As you may have noticed, we don't need two coordinates to fully define a qubit's state. We can get by with one coordinate just as well.
Instead of referring to each state using its cartesian coordinates $psi_0$ and $psi_1$, we can address it using its _polar angle_ $theta$, measured from $#ket("0")$ counterclockwise:
#table(
columns: (1fr,),
align: center,
stroke: none,
align(center, cetz.canvas({
import cetz.draw: *
set-style(content: (frame: "rect", stroke: none, fill: none, padding: .25))
scale(180%)
line(
(0, 1.5),
(0, 0),
(1.5, 0),
stroke: black + 0.25mm,
)
mark((0, 1.5), (0, 2), symbol: ")>", fill: black)
mark((1.5, 0), (2, 0), symbol: ")>", fill: black)
circle((0, 0), radius: 1, stroke: (
paint: black,
thickness: 0.25mm,
dash: "dashed",
))
content((0, 1.5), $p_1$, anchor: "south")
content((1.5, 0), $p_0$, anchor: "west")
circle((0, 1), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.west", $#ket("1")$, anchor: "east")
circle((1, 0), radius: 0.6mm, fill: oblue, stroke: oblue, name: "00")
content("00.south", $#ket("0")$, anchor: "north")
circle((0.87, 0.5), radius: 0.6mm, fill: ored, stroke: ored, name: "00")
content("00.east", $#ket(math.psi)$, anchor: "west")
arc(
(0, 0),
start: 0deg,
stop: 30deg,
anchor: "origin",
radius: 0.6,
name: "a30",
stroke: gray,
)
mark(
"a30.end",
120deg,
symbol: ")>",
fill: gray,
stroke: gray,
)
content("a30.mid", text(fill: gray)[$theta$], anchor: "west")
line((0, 0), (0.87, 0.5), stroke: (
paint: gray,
thickness: 0.4mm,
dash: "dotted",
))
mark(
(0.80, 0.46),
(0.87, 0.5),
symbol: ")>",
fill: gray,
stroke: gray,
)
})),
)
#problem()
Find $psi_0$ and $psi_1$ in terms of $theta$ for an arbitrary qubit $psi$.
#v(1fr)
#pagebreak()
#problem()
Consider the following qubit states:
#grid(
columns: (1fr, 1fr),
$ #ket("+") = (#ket("0") + #ket("1"))/sqrt(2) $,
$ #ket("-") = (#ket("0") - #ket("1"))/sqrt(2) $,
)
- Where are these on the unit circle?
- What are their polar angles?
- What are the probabilities of observing $#ket("0")$ and $#ket("1")$ when measuring $#ket("+")$ and $#ket("-")$?
#table(
columns: (1fr,),
align: center,
stroke: none,
align(center, cetz.canvas({
import cetz.draw: *
set-style(content: (frame: "rect", stroke: none, fill: none, padding: .25))
scale(300%)
line(
(0, 1.3),
(0, 0),
(1.3, 0),
stroke: black + 0.25mm,
)
mark((0, 1.3), (0, 2), symbol: ")>", fill: black)
mark((1.3, 0), (2, 0), symbol: ")>", fill: black)
circle((0, 0), radius: 1, stroke: (
paint: black,
thickness: 0.25mm,
dash: "dashed",
))
content((0, 1.3), $p_1$, anchor: "south")
content((1.3, 0), $p_0$, anchor: "west")
circle((0, 1), radius: 0.4mm, fill: oblue, stroke: oblue, name: "00")
content("00.west", $#ket("1")$, anchor: "east")
circle((1, 0), radius: 0.4mm, fill: oblue, stroke: oblue, name: "00")
content("00.south", $#ket("0")$, anchor: "north")
})),
)
#v(1fr)
#v(1fr)
#v(1fr)
#pagebreak()
= Operations on One Qubit
We may apply transformations to qubits just as we apply transformations to probabilistic bits. Again, we'll represent transformations as $2 times 2$ matrices, since we want to map one qubit state to another.
#note[In other words, we want to map elements of $RR^2$ to elements of $RR^2$.]
We will call such maps _quantum gates,_ since they are the quantum equivalent of classical logic gates.
#v(2mm)
There are two conditions a valid quantum gate $G$ must satisfy:
- For any valid state $#ket([$psi$])$, $G #ket([$psi$])$ is a valid state. Namely, $G$ must preserve the length of any vector it is applied to. Recall that the set of valid quantum states is the set of unit vectors in $RR^2$
- Any quantum gate must be _invertible_. We'll skip this condition for now, and return to it later.
In short, a quantum gate is a linear map that maps the unit circle to itself. There are only two kinds of linear maps that do this: reflections and rotations.
#problem()
The $X$ gate is the quantum analog of the `not` gate, defined by the following table:
- $X #ket("0") = #ket("1")$
- $X #ket("1") = #ket("0")$
Find the matrix $X$.
#solution[
$
mat(0, 1; 1, 0)
$
]
#v(1fr)
#problem()
What is $X #ket("+")$ and $X #ket("-")$?
#hint[Remember that all matrices are linear maps. What does this mean?]
#solution[
$X #ket("+") = #ket("+")$ and $X #ket("-") = - #ket("-")$ (that is, a negative ket-minus). \
Most notably, rememver that $G(a#ket("0") + b #ket("1")) = a G #ket("0") + b G #ket("1")$.
]
#v(1fr)
#problem()
In terms of geometric transformations, what does $X$ do to the unit circle?
#solution[
It is a reflection about the $45degree$ axis.
]
#v(1fr)
#pagebreak()
#problem()
Let $Z$ be a quantum gate defined by the following table:
- $Z #ket("0") = #ket("0")$,
- $Z #ket("1") = -#ket("1")$.
What is the matrix $Z$? What are $Z #ket("+")$ and $Z #ket("-")$?
What is $Z$ as a geometric transformation?
#v(1fr)
#problem()
Is the map $B$ defined by the table below a valid quantum gate?
- $B #ket("0") = #ket("0")$
- $B #ket("1") = #ket("+")$
#hint[Find a $#ket([$psi$])$ so that $B #ket([$psi$])$ is not a valid qubit state]
#solution[
$ B #ket("+") = (1 + sqrt(2))/(2) #ket("0") + 1/2 #ket("1") $
This has a non-unit length of
$
(sqrt(2) + 1)/(2)
$
]
#v(1fr)
#problem("Rotation")
As we noted earlier, any rotation about the center is a valid quantum gate. Let's derive all transformations of this form.
- Let $U_theta$ be the matrix that represents a counterclockwise rotation of $theta$ degrees. What is $U #ket("0")$ and $U #ket("1")$?
- Find the matrix $U_theta$ for an arbitrary $theta$.
#v(1fr)
#problem()
Say we have a qubit that is either $#ket("+")$ or $#ket("-")$. We do not know which of the two states it is in.
Using one operation and one measurement, how can we find out, for certain, which qubit we received?
#v(1fr)

View File

@@ -0,0 +1,126 @@
#import "@local/handout:0.1.0": *
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
= Two Qubits
#definition()
Just as before, we'll represent multi-qubit states as linear combinations of multi-qubit basis states.
For example, a two-qubit state $#ket("ab")$ is the four-dimensional unit vector
$ mat(a; b; c; d) = a #ket("00") + b #ket("01") + c #ket("10") + d #ket("11") $
As always, multi-qubit states are unit vectors. Thus, $a^2 + b^2 + c^2 + d^2 = 1$ in the two-bit case above.
#problem()
Say we have two qubits $#ket([$psi$])$ and $#ket([$phi$])$.
Show that $#ket([$psi$]) times.circle #ket([$phi$])$ is always a unit vector (and is thus a valid quantum state).
#v(1fr)
#definition("Measurement II")<measureii>
Measurement of a two-qubit state works just like measurement of a one-qubit state:
If we measure $a #ket("00") + b #ket("01") + c #ket("10") + d #ket("11")$, we get one of the four basis states with the following probabilities:
- $cal(P)(#ket("00")) = a^2$
- $cal(P)(#ket("01")) = b^2$
- $cal(P)(#ket("10")) = c^2$
- $cal(P)(#ket("11")) = d^2$
As before, the sum of all the above probabilities is $1$.
#problem()
Consider the two-qubit state
$#ket([$psi$]) = 1/sqrt(2) #ket("00") + 1/2 #ket("01") + sqrt(3)/4 #ket("10") + 1/4 #ket("11")$
- If we measure both bits of $#ket([$psi$])$ simultaneously, what is the probability of getting each of $#ket("00")$, $#ket("01")$, $#ket("10")$, and $#ket("11")$?
- If we measure the ONLY the first qubit, what is the probability we get $#ket("0")$? How about $#ket("1")$?
#hint[There are two basis states in which the first qubit is $#ket("0")$.]
- Say we measured the second bit and read $#ket("1")$. If we now measure the first bit, what is the probability of getting $#ket("0")$?
#v(1fr)
#pagebreak()
#problem()
Again, consider the two-qubit state
$#ket([$psi$]) = 1/sqrt(2) #ket("00") + 1/2 #ket("01") + sqrt(3)/4 #ket("10") + 1/4 #ket("11")$
If we measure the first qubit of $#ket([$psi$])$ and get $#ket("0")$, what is the resulting state of $#ket([$psi$])$?
What would the state be if we'd measured $#ket("1")$ instead?
#v(1fr)
#problem()
Consider the three-qubit state $#ket([$psi$]) = c_0 #ket("000") + c_1 #ket("001") + ... + c_7 #ket("111")$.
Say we measure the first two qubits and get $#ket("00")$. What is the resulting state of $#ket([$psi$])$?
#solution[
We measure $#ket("00")$ with probability $c_0^2 + c_1^2$, and $#ket(math.psi)$ collapses to
#v(3mm)
$
(c_0 #ket("000") + c_1 #ket("001"))/(sqrt(c_0^2 + c_1^2))
$
]
#v(1fr)
#pagebreak()
#definition("Entanglement")
Some product states can be factored into a tensor product of individual qubit states. For example,
$
1/2 (#ket("00") + #ket("01") + #ket("10") + #ket("11")) = 1/sqrt(2) (#ket("0") + #ket("1")) times.circle 1/sqrt(2) (#ket("0") + #ket("1"))
$
Such states are called _product states._ States that aren't product states are called _entangled_ states.
#problem()
Factor the following product state:
$
1/(2sqrt(2)) (sqrt(3) #ket("00") - sqrt(3) #ket("01") + #ket("10") - #ket("11"))
$
#solution[
$
(1)/(2 sqrt(2)) (sqrt(3) #ket("00") - sqrt(3) #ket("01") + #ket("10") - #ket("11"))
= (sqrt(3)/2 #ket("0") + 1/2 #ket("1") )
times.circle
( 1/sqrt(2) #ket(0) - 1/sqrt(2) #ket("1"))
$
]
#v(1fr)
#problem()
Show that the following is an entangled state.
$ 1/sqrt(2) #ket("00") + 1/sqrt(2) #ket("11") $
#solution[
$
mat(a_0; a_1)
times.circle
mat(b_0; b_1)
=
a_0b_0 #ket(00) + a_0b_1 #ket(01) + a_1b_0 #ket(10) + a_1b_1 #ket(11)
$
#v(2mm)
So, we have that $a_1b_1 = a_0b_0 = sqrt(2)^(-1)$ \
But $a_0b_1 = a_1b_0 = 0$, so one of $a_0$ and $b_1$ must be zero. \
We thus have a contradiction.
]
#v(1fr)

View File

@@ -0,0 +1,169 @@
#import "@local/handout:0.1.0": *
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
= Logic Gates
#definition("Matrices")
Throughout this handout, we've been using matrices. Again, recall that every linear map may be written as a matrix, and that every matrix represents a linear map. For example, if $f: RR^2 -> RR^2$ is a linear map, we can write it as follows:
$
f(#ket("x")) = mat(m_1, m_2; m_3, m_4) mat(x_1; x_2) = mat(m_1 x_1 + m_2 x_2; m_3 x_1 + m_4 x_2)
$
#definition()
Before we discussing multi-qubit quantum gates, we need to review to classical logic.
Of course, a classical logic gate is a linear map from ${0,1}^m$ to ${0,1}^n$
#problem()<notgatex>
The `not` gate is a map defined by the following table:
- $X #ket("0") = #ket("1")$
- $X #ket("1") = #ket("0")$
Write the `not` gate as a matrix that operates on single-bit vector states.
That is, find a matrix $X$ so that $X mat(1; 0) = mat(0; 1)$ and $X mat(0; 1) = mat(1; 0)$
#solution[
$
X = mat(0, 1; 1, 0)
$
]
#v(1fr)
#problem()
The `and` gate is a map $BB^2 -> BB$ defined by the following table:
#align(center, table(
columns: 3,
stroke: none,
table.hline(),
[`a`], [`b`], [`a` and `b`],
table.hline(),
[0], [0], [0],
[0], [1], [0],
[1], [0], [0],
[1], [1], [1],
table.hline(),
))
Find a matrix $A$ so that $A #ket("ab")$ works as expected.
#hint[Remember, we write bits as vectors.]
#solution[
$
A = mat(1, 1, 1, 0; 0, 0, 0, 1)
$
#instructornote[
Because of the way we represent bits here, we also have the following property: \
The columns of $A$ correspond to the output for each input---i.e, $A$ is just a table of outputs. \
#v(2mm)
For example, if we look at the first column of $A$ (which is $[1, 0]$), we see: \
$A#ket(00) = A[1,0,0,0] = [1,0] = #ket(0)$
#v(2mm)
Also with the last column (which is $[0,1]$): \
$A#ket(00) = A[0,0,0,1] = [0,1] = #ket(1)$
]
]
#v(1fr)
#pagebreak()
#remark()
The way a quantum circuit handles information is a bit different than the way a classical circuit does. We usually think of logic gates as _functions_: they consume one set of bits, and return another/
// TODO: and gate (input a, input b, output)
#v(2mm)
This model, however, won't work for quantum logic. If we want to understand quantum gates, we need to see them not as _functions_, but as _transformations_. This distinction is subtle, but significant:
- functions _consume_ a set of inputs and _produce_ a set of outputs
- transformations _change_ a set of objects, without adding or removing any elements
#v(2mm)
Our usual logic circuit notation models logic gates as functions—we thus can't use it. We'll need a different diagram to draw quantum circuits.
#v(1fr)
First, we'll need a set of bits. For this example, we'll use two, drawn in a vertical array. We'll also add a horizontal time axis, moving from left to right:
#align(center)[
// Quantum circuit diagram showing two qubits over time
#box(width: 10cm, height: 4cm)[
_[Quantum circuit diagram with time axis would go here]_
]
]
In the diagram above, we didn't change our bits—so the labels at the start match those at the end.
#v(1fr)
Thus, our circuit forms a grid, with bits ordered vertically and time horizontally. If we want to change our state, we draw transformations as vertical boxes. Every column represents a single transformation on the entire state:
#align(center)[
// Quantum circuit with transformations
#box(width: 10cm, height: 4cm)[
_[Quantum circuit with transformations $T_1$, $T_2$, $T_3$ would go here]_
]
]
Note that the transformations above span the whole state. This is important: we cannot apply transformations to individual bitswe always transform the _entire_ state.
#v(1fr)
#pagebreak()
*Setup:* Say we want to invert the first bit of a two-bit state. That is, we want a transformation $T$ so that
#align(center)[
// Circuit showing bit flip
#box(width: 8cm, height: 3cm)[
_[Circuit diagram showing first bit flip would go here]_
]
]
In other words, we want a matrix $T$ satisfying the following equalities:
- $T #ket("00") = #ket("10")$
- $T #ket("01") = #ket("11")$
- $T #ket("10") = #ket("00")$
- $T #ket("11") = #ket("01")$
#problem()
Find the matrix that corresponds to the above transformation.
#hint[Remember that $#ket("0") = mat(1; 0)$ and $#ket("1") = mat(0; 1)$. Also, we found earlier that $X = mat(0, 1; 1, 0)$, and of course $I = mat(1, 0; 0, 1)$.]
#v(1fr)
*Remark:* We could draw the above transformation as a combination $X$ and $I$ (identity) gate:
#align(center)[
// Circuit with X and I gates
#box(width: 6cm, height: 3cm)[
_[Circuit diagram with X gate on first qubit, I gate on second would go here]_
]
]
We can even omit the $I$ gate, since we now know that transformations affect the whole state:
#align(center)[
// Simplified circuit with just X gate
#box(width: 6cm, height: 3cm)[
_[Simplified circuit diagram with just X gate on first qubit would go here]_
]
]
We're now done: this is how we draw quantum circuits. Don't forget that transformations _always_ affect the whole stateeven if our diagram doesn't explicitly state this.
#pagebreak()

View File

@@ -0,0 +1,42 @@
#import "@local/handout:0.1.0": *
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
= Quantum Gates
In the previous section, we stated that a quantum gate is a linear map. Let's complete that definition.
#definition()
A quantum gate is a _orthonormal matrix_, which means any gate $G$ satisfies $G G^T = I$.
This implies the following:
- $G$ is square. In other words, it has as many rows as it has columns.
#note[If we think of $G$ as a map, this means that $G$ has as many inputs as it has outputs. This is to be expected: we stated earlier that quantum gates do not destroy or create qubits.]
- $G$ preserves lengths; i.e $|x| = |G x|$.
#note[This ensures that $G #ket([$psi$])$ is always a valid state.]
(You will prove all these properties in any introductory linear algebra course. This isn't a lesson on linear algebra, so you may take them as given today.)
*Remark:* Let $G$ be a quantum gate. Since quantum gates are, by definition, _linear_ maps, the following holds:
$ G(a_0 #ket("0") + a_1 #ket("1")) = a_0 G #ket("0") + a_1 G #ket("1") $
#problem()<cnot>
Consider the _controlled not_ (or _cnot_) gate, defined by the following table:
- $X_c #ket("00") = #ket("00")$
- $X_c #ket("01") = #ket("01")$
- $X_c #ket("10") = #ket("11")$
- $X_c #ket("11") = #ket("10")$
In other words, the cnot gate inverts its second bit if its first bit is $#ket("1")$.
Find the matrix that applies the cnot gate.
#v(1fr)
#pagebreak()

View File

@@ -0,0 +1,53 @@
#import "@local/handout:0.1.0": *
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
= HXH
Let's return to the quantum circuit diagrams we discussed a few pages ago. Keep in mind that we're working with quantum gates and proper qubits—not classical bits, as we were before.
#definition("Controlled Inputs")
A _control input_ or _inverted control input_ may be attached to any gate. These are drawn as filled and empty circles in our circuit diagrams:
#align(center)[
#grid(columns: (1fr, 1fr),
[
// Non-inverted control circuit diagram would go here
#box(width: 6cm, height: 4cm)[
_[Non-inverted control input circuit would go here]_
]
],
[
// Inverted control circuit diagram would go here
#box(width: 6cm, height: 4cm)[
_[Inverted control input circuit would go here]_
]
]
)]
#v(2mm)
An $X$ gate with a (non-inverted) control input behaves like an $X$ gate if _all_ its control inputs are $#ket("1")$, and like $I$ otherwise. An $X$ gate with an inverted control inputs does the opposite, behaving like $I$ if its input is $#ket("1")$ and like $X$ otherwise. The two circuits above illustrate this fact—take a look at their inputs and outputs.
#v(2mm)
Of course, we can give a gate multiple controls. An $X$ gate with multiple controls behaves like an $X$ gate if...
- all non-inverted controls are $#ket("1")$, and
- all inverted controls are $#ket("0")$
...and like $I$ otherwise.
#problem()
What are the final states of the qubits in the diagram below?
#align(center)[
// Multi-control circuit diagram would go here
#box(width: 8cm, height: 6cm)[
_[Multi-control circuit diagram would go here]_
]
]
#v(1fr)
#pagebreak()

View File

@@ -0,0 +1,48 @@
#import "@local/handout:0.1.0": *
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
= Superdense Coding
Consider the following entangled two-qubit states, called the _bell states_:
- $#ket([$Phi^+$]) = 1/sqrt(2) #ket("00") + 1/sqrt(2) #ket("11")$
- $#ket([$Phi^-$]) = 1/sqrt(2) #ket("00") - 1/sqrt(2) #ket("11")$
- $#ket([$Psi^+$]) = 1/sqrt(2) #ket("01") + 1/sqrt(2) #ket("10")$
- $#ket([$Psi^-$]) = 1/sqrt(2) #ket("01") - 1/sqrt(2) #ket("10")$
#problem()
The probabilistic bits we get when measuring any of the above may be called _anticorrelated bits_.
If we measure the first bit of any of these states and observe $1$, what is the resulting compound state?
What if we observe $0$ instead?
Do you see why we can call these bits anticorrelated?
#v(1fr)
#problem()
Show that the bell states are orthogonal
#hint[Dot product]
#v(1fr)
#problem()<bellmeasure>
Say we have a pair of qubits in one of the four bell states.
How can we find out which of the four states we have, with certainty?
#hint[$H #ket("+") = #ket("0")$, and $H #ket("-") = #ket("1")$]
#v(1fr)
#pagebreak()
#definition()
The $Z$ gate is defined as follows:
$ Z mat(psi_0; psi_1) = mat(psi_0; -psi_1) $
#v(1fr)
#pagebreak()

View File

@@ -0,0 +1,31 @@
#import "@local/handout:0.1.0": *
// Define quantum notation macros
#let ket(content) = $|#content angle.r$
#let bra(content) = $angle.l #content|$
= Quantum Teleportation
Superdense coding lets us convert quantum bandwidth into classical bandwidth. Quantum teleportation does the opposite, using two classical bits and an entangled pair to transmit a quantum state.
*Setup:* Again, suppose Alice and Bob each have half of a $#ket([$Phi^+$])$ state. We'll call the state Alice wants to teleport $#ket(math.psi) = psi_0 #ket("0") + psi_1 #ket("1")$.
#problem()
What is the three-qubit state $#ket(math.psi) #ket([$Phi^+$])$ in terms of $psi_0$ and $psi_1$?
#v(1fr)
#problem()
To teleport $#ket(math.psi)$, Alice applies the following circuit to her two qubits, where $#ket([$Phi^+_"A"$])$ is her half of $#ket([$Phi^+$])$. She then measures both qubits and sends the result to Bob.
#align(center)[
// Teleportation circuit diagram would go here
#box(width: 8cm, height: 4cm)[
_[Quantum teleportation circuit diagram would go here]_
]
]
What should Bob do so that $#ket([$Phi^+_"B"$])$ takes the state $#ket(math.psi)$ had initially?
#v(1fr)
#pagebreak()

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
// Shorthand, we'll be using these a lot. // Shorthand, we'll be using these a lot.
@@ -7,31 +7,35 @@
#let tm = sym.times.circle #let tm = sym.times.circle
#let graphgrid(inner_content) = { #let graphgrid(inner_content) = {
align(center, box(inset: 3mm, cetz.canvas({ align(
import cetz.draw: * center,
let x = 5.25 box(
inset: 3mm,
cetz.canvas({
import cetz.draw: *
let x = 5.25
grid( grid(
(0, 0), (0, 0), (x, x), step: 0.75,
(x, x), stroke: luma(100) + 0.3mm
step: 0.75, )
stroke: luma(100) + 0.3mm,
)
if (inner_content != none) { if (inner_content != none) {
inner_content inner_content
} }
mark((0, x + 0.5), (0, x + 1), symbol: ">", fill: black, scale: 1) mark((0, x + 0.5), (0, x + 1), symbol: ">", fill: black, scale: 1)
mark((x + 0.5, 0), (x + 1, 0), symbol: ">", fill: black, scale: 1) mark((x + 0.5, 0), (x + 1, 0), symbol: ">", fill: black, scale: 1)
line( line(
(0, x + 0.25), (0, x + 0.25),
(0, 0), (0, 0),
(x + 0.25, 0), (x + 0.25, 0),
stroke: 0.75mm + black, stroke: 0.75mm + black,
) )
}))) }),
),
)
} }
/// Adds extra padding to an equation. /// Adds extra padding to an equation.
@@ -44,16 +48,23 @@
/// Note that there are newlines between the $ and content, /// Note that there are newlines between the $ and content,
/// this gives us display math (which is what we want when using this macro) /// this gives us display math (which is what we want when using this macro)
#let eqnbox(eqn) = { #let eqnbox(eqn) = {
align(center, box( align(
inset: 3mm, center,
eqn, box(
)) inset: 3mm,
eqn,
),
)
} }
#let dotline(a, b) = { #let dotline(a, b) = {
cetz.draw.line(a, b, stroke: ( cetz.draw.line(
dash: "dashed", a,
thickness: 0.5mm, b,
paint: ored, stroke: (
)) dash: "dashed",
thickness: 0.5mm,
paint: ored,
),
)
} }

View File

@@ -1,18 +1,21 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "../macros.typ": * #import "../macros.typ": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
= Tropical Polynomials = Tropical Polynomials
#definition() #definition()
A _polynomial_ is an expression formed by adding and multiplying numbers and a variable $x$. \ A _polynomial_ is an expression formed by adding and multiplying numbers and a variable $x$. \
Every polynomial can be written as Every polynomial can be written as
#align(center, box( #align(
inset: 3mm, center,
$ box(
c_0 + c_1 x + c_2 x^2 + ... + c_n x^n inset: 3mm,
$, $
)) c_0 + c_1 x + c_2 x^2 + ... + c_n x^n
$,
),
)
for some nonnegative integer $n$ and coefficients $c_0, c_1, ..., c_n$. \ for some nonnegative integer $n$ and coefficients $c_0, c_1, ..., c_n$. \
The _degree_ of a polynomial is the largest $n$ for which $c_n$ is nonzero. The _degree_ of a polynomial is the largest $n$ for which $c_n$ is nonzero.
@@ -40,12 +43,15 @@ In this section, we will analyze tropical polynomials:
#definition() #definition()
A _tropical_ polynomial is a polynomial that uses tropical addition and multiplication. \ A _tropical_ polynomial is a polynomial that uses tropical addition and multiplication. \
In other words, it is an expression of the form In other words, it is an expression of the form
#align(center, box( #align(
inset: 3mm, center,
$ box(
c_0 #tp (c_1 #tm x) #tp (c_2 #tm x^2) #tp ... #tp (c_n #tm x^n) inset: 3mm,
$, $
)) c_0 #tp (c_1 #tm x) #tp (c_2 #tm x^2) #tp ... #tp (c_n #tm x^n)
$,
),
)
where all exponents represent repeated tropical multiplication. where all exponents represent repeated tropical multiplication.
#pagebreak() // MARK: page #pagebreak() // MARK: page
@@ -60,7 +66,7 @@ Draw a graph of the tropical polynomial $f(x) = x^2 #tp 1x #tp 4$. \
#if_no_solutions(graphgrid(none)) #if_no_solutions(graphgrid(none))
#solution([ #solution([
$f(x) = min(2x, 1+x, 4)$, which looks like: $f(x) = min(2x , 1+x, 4)$, which looks like:
#graphgrid({ #graphgrid({
import cetz.draw: * import cetz.draw: *
@@ -84,12 +90,15 @@ Draw a graph of the tropical polynomial $f(x) = x^2 #tp 1x #tp 4$. \
#problem() #problem()
Now, factor $f(x) = x^2 #tp 1x #tp 4$ into two polynomials with degree 1. \ Now, factor $f(x) = x^2 #tp 1x #tp 4$ into two polynomials with degree 1. \
In other words, find $r$ and $s$ so that In other words, find $r$ and $s$ so that
#align(center, box( #align(
inset: 3mm, center,
$ box(
x^2 #tp 1x #tp 4 = (x #tp r)(x #tp s) inset: 3mm,
$, $
)) x^2 #tp 1x #tp 4 = (x #tp r)(x #tp s)
$,
),
)
we will call $r$ and $s$ the _roots_ of $f$. we will call $r$ and $s$ the _roots_ of $f$.
@@ -150,19 +159,15 @@ Find a factorization of $f$ in the form $a(x #tp r)(x#tp s)$.
#solution([ #solution([
We (tropically) factor out $-2$ to get We (tropically) factor out $-2$ to get
#eqnbox( #eqnbox($
$ f(x) = -2(x^2 #tp 2x #tp 10)
f(x) = -2(x^2 #tp 2x #tp 10) $)
$,
)
by the same process as the previous problem, we get by the same process as the previous problem, we get
#eqnbox( #eqnbox($
$ f(x) = -2(x #tp 2)(x #tp 8)
f(x) = -2(x #tp 2)(x #tp 8) $)
$,
)
]) ])
#v(1fr) #v(1fr)
@@ -231,11 +236,11 @@ Graph $f(x) = 1x^2 #tp 3x #tp 5$.
#problem() #problem()
Find a factorization of $f$ in the form $a(x #tp r)(x#tp s)$. Find a factorization of $f$ in the form $a(x #tp r)(x#tp s)$.
#solution(eqnbox( #solution(
$ eqnbox($
f(x) = 1x^2 #tp 3 x #tp 5 = 1(x #tp 2)^2 f(x) = 1x^2 #tp 3 x #tp 5 = 1(x #tp 2)^2
$, $),
)) )
#v(1fr) #v(1fr)
@@ -258,21 +263,23 @@ Graph $f(x) = 2x^2 #tp 4x #tp 4$.
#if_no_solutions(graphgrid(none)) #if_no_solutions(graphgrid(none))
#solution(graphgrid({ #solution(
import cetz.draw: * graphgrid({
let step = 0.75 import cetz.draw: *
let step = 0.75
dotline((0, 2 * step), (3 * step, 8 * step)) dotline((0, 2 * step), (3 * step, 8 * step))
dotline((0, 4 * step), (5 * step, 8 * step)) dotline((0, 4 * step), (5 * step, 8 * step))
dotline((0, 4 * step), (8 * step, 4 * step)) dotline((0, 4 * step), (8 * step, 4 * step))
line( line(
(0, 2 * step), (0, 2 * step),
(1 * step, 4 * step), (1 * step, 4 * step),
(7.5 * step, 4 * step), (7.5 * step, 4 * step),
stroke: 1mm + oblue, stroke: 1mm + oblue,
) )
})) }),
)
#problem() #problem()
@@ -318,7 +325,7 @@ Find a formula for $B$ in terms of $a$, $b$, and $c$. \
#solution([ #solution([
If we want to factor $a(x^2 #tp (b-a)x #tp (c-a))$, we need to find $r$ and $s$ so that If we want to factor $a(x^2 #tp (b-a)x #tp (c-a))$, we need to find $r$ and $s$ so that
- $min(r, s) = b-a$, and - $min(r,s) = b-a$, and
- $r + s = c - a$ - $r + s = c - a$
#v(2mm) #v(2mm)
@@ -334,8 +341,9 @@ Find a formula for $B$ in terms of $a$, $b$, and $c$. \
*Case 2:* If $b > (a + c #sym.div) 2$, then *Case 2:* If $b > (a + c #sym.div) 2$, then
$ $
accent(f, macron)(x) & = a x^2 #tp ((a+c)/2)x #tp c \ accent(f, macron)(x)
& = a(x #tp (c-a)/2)^2 &= a x^2 #tp ((a+c)/2)x #tp c \
&= a(x #tp (c-a)/2)^2
$ $
has the same graph as $f$, and thus $B = (a+c) #sym.div 2$ has the same graph as $f$, and thus $B = (a+c) #sym.div 2$

View File

@@ -1,6 +1,6 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "../macros.typ": * #import "../macros.typ": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
= Tropical Cubic Polynomials = Tropical Cubic Polynomials
@@ -131,12 +131,15 @@ Using the last three problems, find formulas for $B$ and $C$ in terms of $a$, $b
#problem() #problem()
What are the roots of the following polynomial? What are the roots of the following polynomial?
#align(center, box( #align(
inset: 3mm, center,
$ box(
3 x^6 #tp 4 x^5 #tp 2 x^4 #tp x^3 #tp x^2 #tp 4 x #tp 5 inset: 3mm,
$, $
)) 3 x^6 #tp 4 x^5 #tp 2 x^4 #tp x^3 #tp x^2 #tp 4 x #tp 5
$,
),
)
#solution([ #solution([
We have We have
@@ -166,8 +169,9 @@ Find a formula for each $C_i$ in terms of $c_0, c_1, ..., c_n$.
#solution([ #solution([
$ $
A_j & = min_(l<=j<k)( (a_l - a_k) / (k-l) (k-j) + a_k ) \ A_j
& = min_(l<=j<k)( a_l (k-j) / (k-l) + a_k (j-l) / (k-l) ) &= min_(l<=j<k)( (a_l - a_k) / (k-l) (k-j) + a_k ) \
&= min_(l<=j<k)( a_l (k-j) / (k-l) + a_k (j-l) / (k-l) )
$ $
#v(2mm) #v(2mm)

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
= Wallpaper Symmetries = Wallpaper Symmetries

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
= Mirror Symmetry = Mirror Symmetry

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
= Rotational Symmetry = Rotational Symmetry

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#let pat(img, sol) = { #let pat(img, sol) = {
problem() problem()

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
= The Signature-Cost Theorem = The Signature-Cost Theorem
@@ -7,20 +7,23 @@
First, we'll associate a _cost_ to each type of symmetry in orbifold notation: First, we'll associate a _cost_ to each type of symmetry in orbifold notation:
#v(4mm) #v(4mm)
#align(center, table( #align(
stroke: (1pt, 1pt), center,
align: center, table(
columns: (auto, auto, auto, auto), stroke: (1pt, 1pt),
[*Symbol*], [*Cost*], [*Symbol*], [*Cost*], align: center,
[#sym.circle.small], [2], [#sym.times or #sym.convolve], [1], columns: (auto, auto, auto, auto),
[#sym.diamond.stroked.small`2`], [1/2], [#sym.convolve`2`], [1/4], [*Symbol*], [*Cost*], [*Symbol*], [*Cost*],
[#sym.diamond.stroked.small`3`], [2/3], [#sym.convolve`3`], [1/3], [#sym.circle.small], [2], [#sym.times or #sym.convolve], [1],
[#sym.dots], [#sym.dots], [#sym.dots], [#sym.dots], [#sym.diamond.stroked.small`2`], [1/2], [#sym.convolve`2`], [1/4],
[#sym.diamond.stroked.small`n`], [#sym.diamond.stroked.small`3`], [2/3], [#sym.convolve`3`], [1/3],
[$(n-1) / n$], [#sym.dots], [#sym.dots], [#sym.dots], [#sym.dots],
[#sym.convolve`n`], [#sym.diamond.stroked.small`n`],
[$(n-1) / (2n)$], [$(n-1) / n$],
)) [#sym.convolve`n`],
[$(n-1) / (2n)$],
),
)
We then calculate the total "cost" of a signature by adding up the costs of each component. We then calculate the total "cost" of a signature by adding up the costs of each component.

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#show: handout.with( #show: handout.with(
title: [Warm-Up: Big-Tac-Toe], title: [Warm-Up: Big-Tac-Toe],
@@ -75,13 +75,16 @@ How does your strategy change? \
#if extra_boards { #if extra_boards {
pagebreak() pagebreak()
align(center, grid( align(
stroke: none, center,
align: center, grid(
columns: (1fr, 1fr), stroke: none,
rows: (1fr, 1fr, 1fr), align: center,
btt(0.35), btt(0.35), columns: (1fr, 1fr),
btt(0.35), btt(0.35), rows: (1fr, 1fr, 1fr),
btt(0.35), btt(0.35), btt(0.35), btt(0.35),
)) btt(0.35), btt(0.35),
btt(0.35), btt(0.35),
),
)
} }

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#show: handout.with( #show: handout.with(
@@ -43,56 +43,61 @@ Now, consider the set of six-sided dice below:
- Die $E$: $0, 5, 5, 5, 5, 5$ - Die $E$: $0, 5, 5, 5, 5, 5$
On average, which die beats each of the others? Draw a diagram. On average, which die beats each of the others? Draw a diagram.
#solution(align(center, cetz.canvas({ #solution(
import cetz.draw: * align(
center,
cetz.canvas({
import cetz.draw: *
let s = 0.8 // Scale let s = 0.8 // Scale
let t = 13pt * s // text size let t = 13pt * s // text size
let radius = 0.3 * s let radius = 0.3 * s
// Points // Points
let a = (-2 * s, 0.2 * s) let a = (-2 * s, 0.2 * s)
let b = (0 * s, 2 * s) let b = (0 * s, 2 * s)
let c = (2 * s, 0.2 * s) let c = (2 * s, 0.2 * s)
let d = (1.2 * s, -2.1 * s) let d = (1.2 * s, -2.1 * s)
let e = (-1.2 * s, -2.1 * s) let e = (-1.2 * s, -2.1 * s)
set-style( set-style(
stroke: (thickness: 0.6mm * s), stroke: (thickness: 0.6mm * s),
mark: ( mark: (
end: ( end: (
symbol: ">", symbol: ">",
fill: black, fill: black,
offset: radius + (0.025 * s), offset: radius + (0.025 * s),
width: 1.2mm * s, width: 1.2mm * s,
length: 1.2mm * s, length: 1.2mm * s,
), ),
), ),
) )
line(a, b) line(a, b)
line(b, c) line(b, c)
line(c, d) line(c, d)
line(d, e) line(d, e)
line(e, a) line(e, a)
line(a, c) line(a, c)
line(b, d) line(b, d)
line(c, e) line(c, e)
line(d, a) line(d, a)
line(e, b) line(e, b)
circle(a, radius: radius, fill: oblue, stroke: none) circle(a, radius: radius, fill: oblue, stroke: none)
circle(b, radius: radius, fill: oblue, stroke: none) circle(b, radius: radius, fill: oblue, stroke: none)
circle(c, radius: radius, fill: oblue, stroke: none) circle(c, radius: radius, fill: oblue, stroke: none)
circle(d, radius: radius, fill: oblue, stroke: none) circle(d, radius: radius, fill: oblue, stroke: none)
circle(e, radius: radius, fill: oblue, stroke: none) circle(e, radius: radius, fill: oblue, stroke: none)
content(a, text(fill: white, size: t, [*A*])) content(a, text(fill: white, size: t, [*A*]))
content(b, text(fill: white, size: t, [*B*])) content(b, text(fill: white, size: t, [*B*]))
content(c, text(fill: white, size: t, [*C*])) content(c, text(fill: white, size: t, [*C*]))
content(d, text(fill: white, size: t, [*D*])) content(d, text(fill: white, size: t, [*D*]))
content(e, text(fill: white, size: t, [*E*])) content(e, text(fill: white, size: t, [*E*]))
}))) }),
),
)
#v(1fr) #v(1fr)

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#show: handout.with( #show: handout.with(
title: [Warm-Up: What's an AST?], title: [Warm-Up: What's an AST?],
@@ -18,56 +18,59 @@ You may detach the string as you hang the painting, but it must be re-attached o
#v(2mm) #v(2mm)
#align(center, cetz.canvas({ #align(
import cetz.draw: * center,
let s = 2.5 cetz.canvas({
import cetz.draw: *
let s = 2.5
line( line(
(0 * s, 1 * s), (0 * s, 1 * s),
(2 * s, 1 * s), (2 * s, 1 * s),
(2 * s, 0 * s), (2 * s, 0 * s),
(0 * s, 0 * s), (0 * s, 0 * s),
close: true, close: true,
stroke: (thickness: 0.8mm), stroke: (thickness: 0.8mm),
) )
line( line(
(0.1 * s, 1 * s), (0.1 * s, 1 * s),
(0.5 * s, 1.5 * s), (0.5 * s, 1.5 * s),
(1.5 * s, 1.5 * s), (1.5 * s, 1.5 * s),
(1.9 * s, 1 * s), (1.9 * s, 1 * s),
stroke: (thickness: 0.5mm, dash: "dotted"), stroke: (thickness: 0.5mm, dash: "dotted"),
) )
circle((0.5 * s, 1.5 * s), radius: 0.04 * s, fill: black, stroke: none) circle((0.5 * s, 1.5 * s), radius: 0.04 * s, fill: black, stroke: none)
circle((1.5 * s, 1.5 * s), radius: 0.04 * s, fill: black, stroke: none) circle((1.5 * s, 1.5 * s), radius: 0.04 * s, fill: black, stroke: none)
line( line(
(0.66 * s, 0.66 * s), (0.66 * s, 0.66 * s),
(0.66 * s, 0.35 * s), (0.66 * s, 0.35 * s),
(0.60 * s, 0.1 * s), (0.60 * s, 0.1 * s),
) )
line( line(
(0.72 * s, 0.1 * s), (0.72 * s, 0.1 * s),
(0.66 * s, 0.35 * s), (0.66 * s, 0.35 * s),
) )
line( line(
(0.66 * s, 0.575 * s), (0.66 * s, 0.575 * s),
(0.6 * s, 0.475 * s), (0.6 * s, 0.475 * s),
(0.525 * s, 0.575 * s), (0.525 * s, 0.575 * s),
) )
line( line(
(0.66 * s, 0.575 * s), (0.66 * s, 0.575 * s),
(0.72 * s, 0.475 * s), (0.72 * s, 0.475 * s),
(0.795 * s, 0.575 * s), (0.795 * s, 0.575 * s),
) )
circle((0.66 * s, 0.66 * s), radius: 0.07 * s, fill: white) circle((0.66 * s, 0.66 * s), radius: 0.07 * s, fill: white)
})) }),
)
#solution([ #solution([
Say we have a left nail and a right nail. The path of the string is as follows: Say we have a left nail and a right nail. The path of the string is as follows:

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#show: handout.with( #show: handout.with(
title: [Warm-Up: Passing Balls], title: [Warm-Up: Passing Balls],
@@ -78,25 +78,32 @@ Participant 1 has a black ball. Which balls are held by participants 2, 3, and 4
let i = 1 let i = 1
for p in pts { for p in pts {
circle(p, radius: radius * s, fill: if i == 1 { circle(
ored p,
} else if i == 2 { radius: radius * s,
ogreen fill: if i == 1 {
} else if i == 3 { ored
oorange } else if i == 2 {
} else if i == 4 { ogreen
oblue } else if i == 3 {
} else { white }) oorange
} else if i == 4 {
oblue
} else { white },
)
content(p, text( content(
fill: if i <= 4 { p,
white text(
} else { fill: if i <= 4 {
black white
}, } else {
size: t, black
[*#i*], },
)) size: t,
[*#i*],
),
)
i = i + 1 i = i + 1
} }
}), }),
@@ -111,25 +118,32 @@ Participant 1 has a black ball. Which balls are held by participants 2, 3, and 4
let l = calc.rem(((i - 1) * 5), 12) + 1 let l = calc.rem(((i - 1) * 5), 12) + 1
circle(p, radius: radius * s, fill: if l == 1 { circle(
ored p,
} else if l == 2 { radius: radius * s,
ogreen fill: if l == 1 {
} else if l == 3 { ored
oorange } else if l == 2 {
} else if l == 4 { ogreen
oblue } else if l == 3 {
} else { white }) oorange
} else if l == 4 {
oblue
} else { white },
)
content(p, text( content(
fill: if l <= 4 { p,
white text(
} else { fill: if l <= 4 {
black white
}, } else {
size: t, black
[*#l*], },
)) size: t,
[*#l*],
),
)
i = i + 1 i = i + 1
} }
}), }),
@@ -144,25 +158,32 @@ Participant 1 has a black ball. Which balls are held by participants 2, 3, and 4
let l = calc.rem(((i - 1) * 5), 12) + 1 let l = calc.rem(((i - 1) * 5), 12) + 1
circle(p, radius: radius * s, fill: if l == 1 { circle(
oblue p,
} else if l == 2 { radius: radius * s,
oorange fill: if l == 1 {
} else if l == 3 { oblue
ored } else if l == 2 {
} else if l == 4 { oorange
ogreen } else if l == 3 {
} else { white }) ored
} else if l == 4 {
ogreen
} else { white },
)
content(p, text( content(
fill: if l <= 4 { p,
white text(
} else { fill: if l <= 4 {
black white
}, } else {
size: t, black
[*#l*], },
)) size: t,
[*#l*],
),
)
i = i + 1 i = i + 1
} }
}), }),

View File

@@ -1,5 +1,5 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#show: handout.with( #show: handout.with(
title: [Warm-Up: What's an AST?], title: [Warm-Up: What's an AST?],
@@ -24,48 +24,51 @@ respecting the order of operations $[and, times, div, +, -]$.
#v(2mm) #v(2mm)
#align(center, cetz.canvas({ #align(
import cetz.draw: * center,
cetz.canvas({
import cetz.draw: *
// spell:off // spell:off
content((0, 0), $+$, name: "r") content((0, 0), $+$, name: "r")
content((-0.5, -1), $3$, name: "a") content((-0.5, -1), $3$, name: "a")
content((0.5, -1), $div$, name: "b") content((0.5, -1), $div$, name: "b")
content((-0.3, -2), $times$, name: "ba") content((-0.3, -2), $times$, name: "ba")
content((1.3, -2), $and$, name: "bb") content((1.3, -2), $and$, name: "bb")
content((-0.8, -3), $9$, name: "baa") content((-0.8, -3), $9$, name: "baa")
content((0.2, -3), $8$, name: "bab") content((0.2, -3), $8$, name: "bab")
content((0.8, -3), $5$, name: "bba") content((0.8, -3), $5$, name: "bba")
content((1.8, -3), $6$, name: "bbb") content((1.8, -3), $6$, name: "bbb")
// spell:on // spell:on
// Zero-sized arrows are a hack for offset. // Zero-sized arrows are a hack for offset.
set-style( set-style(
stroke: (thickness: 0.3mm), stroke: (thickness: 0.3mm),
mark: ( mark: (
start: ( start: (
symbol: "|", symbol: "|",
offset: 0.25, offset: 0.25,
width: 0mm, width: 0mm,
length: 0mm, length: 0mm,
),
end: (
symbol: "|",
offset: 0.25,
width: 0mm,
length: 0mm,
),
), ),
end: ( )
symbol: "|",
offset: 0.25,
width: 0mm,
length: 0mm,
),
),
)
// spell:off // spell:off
line("r", "a") line("r", "a")
line("r", "b") line("r", "b")
line("b", "ba") line("b", "ba")
line("b", "bb") line("b", "bb")
line("ba", "baa") line("ba", "baa")
line("ba", "bab") line("ba", "bab")
line("bb", "bba") line("bb", "bba")
line("bb", "bbb") line("bb", "bbb")
// spell:on // spell:on
})) }),
)

View File

@@ -1,21 +1,24 @@
#import "@local/handout:0.1.0": * #import "@local/handout:0.1.0": *
#import "@preview/cetz:0.4.2" #import "@preview/cetz:0.3.1"
#show: handout.with( #show: handout.with(
title: [Warm-Up: Wild Tic-Tac-Toe], title: [Warm-Up: Wild Tic-Tac-Toe],
by: "Mark", by: "Mark",
) )
#let ttt = align(center, cetz.canvas({ #let ttt = align(
import cetz.draw: * center,
let s = 0.7 // scale cetz.canvas({
import cetz.draw: *
let s = 0.7 // scale
set-style(stroke: (thickness: 0.5mm * s)) set-style(stroke: (thickness: 0.5mm * s))
line((-1 * s, 3 * s), (-1 * s, -3 * s)) line((-1 * s, 3 * s), (-1 * s, -3 * s))
line((1 * s, 3 * s), (1 * s, -3 * s)) line((1 * s, 3 * s), (1 * s, -3 * s))
line((3 * s, -1 * s), (-3 * s, -1 * s)) line((3 * s, -1 * s), (-3 * s, -1 * s))
line((3 * s, 1 * s), (-3 * s, 1 * s)) line((3 * s, 1 * s), (-3 * s, 1 * s))
})) }),
)
#problem() #problem()