Skip to content

Commit 1b9172b

Browse files
authored
Merge pull request #438 from Strilanc/dev-e
Development of v2.3
2 parents 69373f5 + 68aba93 commit 1b9172b

66 files changed

Lines changed: 1265 additions & 300 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.travis.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ node_js: 5.1
44
install: npm install
55
branches:
66
only: master
7-
before_script:
8-
- export DISPLAY=:99.0
9-
- sh -e /etc/init.d/xvfb start
7+
services:
8+
- xvfb
109
script: npm run test-travis
1110
addons:
1211
firefox: "latest"

html/forge.partial.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<td>
2727
<input tabindex="100" id='gate-forge-rotation-axis' type="text" size="8" placeholder="X+Z"> axis<br/>
2828
<input tabindex="101" id='gate-forge-rotation-angle' type="text" size="8" placeholder="45" style="margin:0.5em 0 0 0;">° angle<br/>
29-
<input tabindex="102" id='gate-forge-rotation-phase' type="text" size="8" placeholder="0" style="margin:0.5em 0 0 0;">° phase
29+
<input tabindex="102" id='gate-forge-rotation-phase' type="text" size="8" placeholder="0" style="margin:0.5em 0 0 0;">° global phase
3030
</td>
3131
<td></td>
3232
<td>

html/quirk.template.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
&nbsp;
3636
&nbsp;
3737
&nbsp;
38-
<span style="color:#BBB">Version 2.2</span>
38+
<span style="color:#BBB">Version 2.3</span>
3939
</div>
4040

4141
<!-- Circuit drawing area -->

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"title": "Quirk",
44
"description": "A drag-and-drop toy for exploring and understanding small quantum circuits.",
55
"license": "Apache-2.0",
6-
"version": "2.2.0",
6+
"version": "2.3.0",
77
"homepage": "https://github.com/Strilanc/Quirk",
88
"bugs": {
99
"url": "https://github.com/Strilanc/Quirk/issues"

src/base/Util.js

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,24 @@ class Util {
152152
return p;
153153
}
154154

155+
/**
156+
* Counts the number of set bits in an integer.
157+
*
158+
* @param {!int} i
159+
* @returns {!int}
160+
*/
161+
static popcnt(i) {
162+
if (i < 0) {
163+
return Math.POSITIVE_INFINITY;
164+
}
165+
let t = 0;
166+
while (i > 0) {
167+
i &= i - 1;
168+
t++;
169+
}
170+
return t;
171+
}
172+
155173
/**
156174
* Determines how multiply-even a number is; how many times you can divide it by 2 before getting an odd result.
157175
* Odd numbers have 0 power-of-two-ness, multiples of 2 that aren't multiples of 4 have 1 power-of-two-ness,
@@ -160,18 +178,19 @@ class Util {
160178
* Note that zero has infinite power-of-two-ness.
161179
*
162180
* @param {!int} i
163-
* @returns {!int}
181+
* @param {T=} zeroResult The value to return when i == 0. Defaults to positive infinity (because you can divide
182+
* zero by two as many times as you want and still get an integer).
183+
* @returns {T|!int}
184+
* @template T
164185
*/
165-
static powerOfTwoness(i) {
186+
static powerOfTwoness(i, zeroResult=Math.POSITIVE_INFINITY) {
166187
if (i === 0) {
167-
return Math.POSITIVE_INFINITY;
188+
return zeroResult;
168189
}
169190
if (i < 0) {
170-
return Util.powerOfTwoness(-i);
191+
return Util.powerOfTwoness(-i, zeroResult);
171192
}
172-
let lowMask = i ^ (i - 1);
173-
let lowBit = i & lowMask;
174-
return Math.round(Math.log2(lowBit));
193+
return Math.round(Math.log2(i & ~(i - 1)));
175194
}
176195

177196
/**

src/circuit/CircuitComputeUtil.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ function _extractStateStatsNeededByCircuitColumn(
133133
circuitDefinition.numWires,
134134
ctx.controls,
135135
ctx.controlsTexture,
136+
ctx.controls,
136137
ctx.stateTrader,
137138
Util.mergeMaps(
138139
ctx.customContextFromGates,
@@ -185,6 +186,7 @@ function _advanceStateWithCircuitDefinitionColumn(
185186
ctx.wireCount,
186187
ctx.controls,
187188
ctx.controlsTexture,
189+
controls,
188190
trader,
189191
colContext);
190192
let mainCtx = new CircuitEvalContext(
@@ -193,6 +195,7 @@ function _advanceStateWithCircuitDefinitionColumn(
193195
ctx.wireCount,
194196
controls,
195197
controlTex,
198+
controls,
196199
trader,
197200
colContext);
198201

src/circuit/CircuitDefinition.js

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,17 @@ class CircuitDefinition {
142142

143143
/**
144144
* @param {!int} wire
145+
* @param {!int=} newStateIndex=
145146
* @returns {!CircuitDefinition}
146147
*/
147-
withSwitchedInitialStateOn(wire) {
148+
withSwitchedInitialStateOn(wire, newStateIndex=undefined) {
148149
let m = new Map([...this.customInitialValues.entries()]);
149150
let v = m.get(wire);
150151
let cycle = [...INITIAL_STATES_TO_GATES.keys()];
151152
let newVal = cycle[(cycle.indexOf(v) + 1) % cycle.length];
153+
if (newStateIndex !== undefined) {
154+
newVal = newStateIndex;
155+
}
152156
if (newVal === undefined) {
153157
m.delete(wire);
154158
} else {
@@ -876,18 +880,30 @@ class CircuitDefinition {
876880
if (col < 0 || col >= this.columns.length) {
877881
return Controls.NONE;
878882
}
879-
let result = Controls.NONE;
880883
let column = this.columns[col];
884+
let includeMask = 0;
885+
let desireMask = 0;
886+
let parityMask = 0;
881887
for (let i = 0; i < column.gates.length; i++) {
882888
let gate = column.gates[i];
883889
if (gate !== undefined && this.gateAtLocIsDisabledReason(col, i) === undefined) {
884890
let bit = gate.controlBit();
885-
if (bit !== undefined) {
886-
result = result.and(Controls.bit(i, bit));
891+
if (bit === 'parity') {
892+
parityMask |= 1 << i;
893+
} else if (bit !== undefined) {
894+
includeMask |= 1 << i;
895+
if (bit) {
896+
desireMask |= 1 << i;
897+
}
887898
}
888899
}
889900
}
890-
return result;
901+
if (parityMask !== 0) {
902+
let parityBit = parityMask & ~(parityMask - 1);
903+
desireMask |= parityBit;
904+
includeMask |= parityBit;
905+
}
906+
return new Controls(includeMask, desireMask, parityMask);
891907
}
892908

893909
/**

src/circuit/CircuitEvalContext.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class CircuitEvalContext {
2626
* @param {!int} wireCount
2727
* @param {!Controls} controls
2828
* @param {!WglTexture} controlsTexture
29+
* @param {!Controls} rawControls The controls of the gate column, made available so that before/after operations
30+
* can use this information (even though they are not themselves controlled).
2931
* @param {!WglTextureTrader} stateTrader
3032
* @param {!Map.<!string, *>} customContextFromGates
3133
*/
@@ -34,6 +36,7 @@ class CircuitEvalContext {
3436
wireCount,
3537
controls,
3638
controlsTexture,
39+
rawControls,
3740
stateTrader,
3841
customContextFromGates) {
3942
/** @type {!number} */
@@ -47,6 +50,8 @@ class CircuitEvalContext {
4750
this.wireCount = wireCount;
4851
/** @type {!Controls} */
4952
this.controls = controls;
53+
/** @type {!Controls} */
54+
this.rawControls = rawControls;
5055
/** @type {!WglTexture} */
5156
this.controlsTexture = controlsTexture;
5257
/** @type {!WglTextureTrader} */
@@ -75,6 +80,7 @@ class CircuitEvalContext {
7580
this.wireCount,
7681
this.controls,
7782
this.controlsTexture,
83+
this.rawControls,
7884
this.stateTrader,
7985
this.customContextFromGates);
8086
}

src/circuit/CircuitStats.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ class CircuitStats {
344344
numWires,
345345
Controls.NONE,
346346
controlTex,
347+
Controls.NONE,
347348
stateTrader,
348349
new Map()),
349350
circuitDefinition,

src/circuit/Controls.js

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,25 @@ class Controls {
2525
/**
2626
* @param {!int} inclusionMask.
2727
* @param {!int} desiredValueMask
28+
* @param {!int=0} parityMask
2829
* @property {!int} inclusionMask.
2930
* @property {!int} desiredValueMask
3031
*/
31-
constructor(inclusionMask, desiredValueMask) {
32+
constructor(inclusionMask, desiredValueMask, parityMask=0) {
3233
if ((desiredValueMask & ~inclusionMask) !== 0) {
3334
throw new DetailedError("Desired un-included bits", {inclusionMask, desiredValueMask});
3435
}
36+
if (parityMask !== 0 && Util.popcnt(inclusionMask & parityMask) !== 1) {
37+
throw new DetailedError("Exactly one parity bit must be in the inclusion mask",
38+
{inclusionMask, parityMask});
39+
}
40+
3541
/** @type {!int} */
3642
this.inclusionMask = inclusionMask;
3743
/** @type {!int} */
3844
this.desiredValueMask = desiredValueMask;
45+
/** @type {!int} */
46+
this.parityMask = parityMask;
3947
}
4048

4149
/**
@@ -57,7 +65,8 @@ class Controls {
5765
isEqualTo(other) {
5866
return other instanceof Controls &&
5967
this.inclusionMask === other.inclusionMask &&
60-
this.desiredValueMask === other.desiredValueMask;
68+
this.desiredValueMask === other.desiredValueMask &&
69+
this.parityMask === other.parityMask;
6170
}
6271

6372
/**
@@ -68,12 +77,20 @@ class Controls {
6877
return "No Controls";
6978
}
7079

71-
return "Controls: ...__" + Seq.naturals().
72-
takeWhile(i => (1<<i) <= this.inclusionMask).
73-
map(this.desiredValueFor.bind(this)).
80+
let range = Seq.naturals().takeWhile(i => (1<<i) <= (this.inclusionMask | this.parityMask));
81+
let result = "Controls: ...__" + range.
82+
map(e => this.desiredValueFor(e)).
7483
map(e => e === undefined ? "_" : e ? "1" : "0").
7584
reverse().
7685
join("");
86+
if (this.parityMask !== 0) {
87+
result += "\n parity: ...__" + range.
88+
map(e => this.parityMask & (1 << e)).
89+
map(e => e ? "1" : "_").
90+
reverse().
91+
join("")
92+
}
93+
return result;
7794
}
7895

7996
/**
@@ -113,9 +130,13 @@ class Controls {
113130
if ((other.desiredValueMask & this.inclusionMask) !== (this.desiredValueMask & other.inclusionMask)) {
114131
throw new DetailedError("Contradictory controls.", {"this": this, other})
115132
}
133+
if ((other.parityMask & this.inclusionMask) !== 0 || (this.parityMask & other.inclusionMask) !== 0) {
134+
throw new DetailedError("Can't intersect parity controls.", {"this": this, other})
135+
}
116136
return new Controls(
117137
this.inclusionMask | other.inclusionMask,
118-
this.desiredValueMask | other.desiredValueMask);
138+
this.desiredValueMask | other.desiredValueMask,
139+
this.parityMask | other.parityMask);
119140
}
120141

121142
/**
@@ -125,7 +146,8 @@ class Controls {
125146
shift(offset) {
126147
return new Controls(
127148
this.inclusionMask << offset,
128-
this.desiredValueMask << offset)
149+
this.desiredValueMask << offset,
150+
this.parityMask << offset)
129151
}
130152
}
131153

0 commit comments

Comments
 (0)