Skip to content

Commit

Permalink
Merge pull request #438 from Strilanc/dev-e
Browse files Browse the repository at this point in the history
Development of v2.3
  • Loading branch information
Strilanc authored Sep 11, 2019
2 parents 69373f5 + 68aba93 commit 1b9172b
Show file tree
Hide file tree
Showing 66 changed files with 1,265 additions and 300 deletions.
5 changes: 2 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ node_js: 5.1
install: npm install
branches:
only: master
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
services:
- xvfb
script: npm run test-travis
addons:
firefox: "latest"
2 changes: 1 addition & 1 deletion html/forge.partial.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<td>
<input tabindex="100" id='gate-forge-rotation-axis' type="text" size="8" placeholder="X+Z"> axis<br/>
<input tabindex="101" id='gate-forge-rotation-angle' type="text" size="8" placeholder="45" style="margin:0.5em 0 0 0;">° angle<br/>
<input tabindex="102" id='gate-forge-rotation-phase' type="text" size="8" placeholder="0" style="margin:0.5em 0 0 0;">° phase
<input tabindex="102" id='gate-forge-rotation-phase' type="text" size="8" placeholder="0" style="margin:0.5em 0 0 0;">° global phase
</td>
<td></td>
<td>
Expand Down
2 changes: 1 addition & 1 deletion html/quirk.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
&nbsp;
&nbsp;
&nbsp;
<span style="color:#BBB">Version 2.2</span>
<span style="color:#BBB">Version 2.3</span>
</div>

<!-- Circuit drawing area -->
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"title": "Quirk",
"description": "A drag-and-drop toy for exploring and understanding small quantum circuits.",
"license": "Apache-2.0",
"version": "2.2.0",
"version": "2.3.0",
"homepage": "https://github.com/Strilanc/Quirk",
"bugs": {
"url": "https://github.com/Strilanc/Quirk/issues"
Expand Down
33 changes: 26 additions & 7 deletions src/base/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,24 @@ class Util {
return p;
}

/**
* Counts the number of set bits in an integer.
*
* @param {!int} i
* @returns {!int}
*/
static popcnt(i) {
if (i < 0) {
return Math.POSITIVE_INFINITY;
}
let t = 0;
while (i > 0) {
i &= i - 1;
t++;
}
return t;
}

/**
* Determines how multiply-even a number is; how many times you can divide it by 2 before getting an odd result.
* Odd numbers have 0 power-of-two-ness, multiples of 2 that aren't multiples of 4 have 1 power-of-two-ness,
Expand All @@ -160,18 +178,19 @@ class Util {
* Note that zero has infinite power-of-two-ness.
*
* @param {!int} i
* @returns {!int}
* @param {T=} zeroResult The value to return when i == 0. Defaults to positive infinity (because you can divide
* zero by two as many times as you want and still get an integer).
* @returns {T|!int}
* @template T
*/
static powerOfTwoness(i) {
static powerOfTwoness(i, zeroResult=Math.POSITIVE_INFINITY) {
if (i === 0) {
return Math.POSITIVE_INFINITY;
return zeroResult;
}
if (i < 0) {
return Util.powerOfTwoness(-i);
return Util.powerOfTwoness(-i, zeroResult);
}
let lowMask = i ^ (i - 1);
let lowBit = i & lowMask;
return Math.round(Math.log2(lowBit));
return Math.round(Math.log2(i & ~(i - 1)));
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/circuit/CircuitComputeUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ function _extractStateStatsNeededByCircuitColumn(
circuitDefinition.numWires,
ctx.controls,
ctx.controlsTexture,
ctx.controls,
ctx.stateTrader,
Util.mergeMaps(
ctx.customContextFromGates,
Expand Down Expand Up @@ -185,6 +186,7 @@ function _advanceStateWithCircuitDefinitionColumn(
ctx.wireCount,
ctx.controls,
ctx.controlsTexture,
controls,
trader,
colContext);
let mainCtx = new CircuitEvalContext(
Expand All @@ -193,6 +195,7 @@ function _advanceStateWithCircuitDefinitionColumn(
ctx.wireCount,
controls,
controlTex,
controls,
trader,
colContext);

Expand Down
26 changes: 21 additions & 5 deletions src/circuit/CircuitDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,17 @@ class CircuitDefinition {

/**
* @param {!int} wire
* @param {!int=} newStateIndex=
* @returns {!CircuitDefinition}
*/
withSwitchedInitialStateOn(wire) {
withSwitchedInitialStateOn(wire, newStateIndex=undefined) {
let m = new Map([...this.customInitialValues.entries()]);
let v = m.get(wire);
let cycle = [...INITIAL_STATES_TO_GATES.keys()];
let newVal = cycle[(cycle.indexOf(v) + 1) % cycle.length];
if (newStateIndex !== undefined) {
newVal = newStateIndex;
}
if (newVal === undefined) {
m.delete(wire);
} else {
Expand Down Expand Up @@ -876,18 +880,30 @@ class CircuitDefinition {
if (col < 0 || col >= this.columns.length) {
return Controls.NONE;
}
let result = Controls.NONE;
let column = this.columns[col];
let includeMask = 0;
let desireMask = 0;
let parityMask = 0;
for (let i = 0; i < column.gates.length; i++) {
let gate = column.gates[i];
if (gate !== undefined && this.gateAtLocIsDisabledReason(col, i) === undefined) {
let bit = gate.controlBit();
if (bit !== undefined) {
result = result.and(Controls.bit(i, bit));
if (bit === 'parity') {
parityMask |= 1 << i;
} else if (bit !== undefined) {
includeMask |= 1 << i;
if (bit) {
desireMask |= 1 << i;
}
}
}
}
return result;
if (parityMask !== 0) {
let parityBit = parityMask & ~(parityMask - 1);
desireMask |= parityBit;
includeMask |= parityBit;
}
return new Controls(includeMask, desireMask, parityMask);
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/circuit/CircuitEvalContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class CircuitEvalContext {
* @param {!int} wireCount
* @param {!Controls} controls
* @param {!WglTexture} controlsTexture
* @param {!Controls} rawControls The controls of the gate column, made available so that before/after operations
* can use this information (even though they are not themselves controlled).
* @param {!WglTextureTrader} stateTrader
* @param {!Map.<!string, *>} customContextFromGates
*/
Expand All @@ -34,6 +36,7 @@ class CircuitEvalContext {
wireCount,
controls,
controlsTexture,
rawControls,
stateTrader,
customContextFromGates) {
/** @type {!number} */
Expand All @@ -47,6 +50,8 @@ class CircuitEvalContext {
this.wireCount = wireCount;
/** @type {!Controls} */
this.controls = controls;
/** @type {!Controls} */
this.rawControls = rawControls;
/** @type {!WglTexture} */
this.controlsTexture = controlsTexture;
/** @type {!WglTextureTrader} */
Expand Down Expand Up @@ -75,6 +80,7 @@ class CircuitEvalContext {
this.wireCount,
this.controls,
this.controlsTexture,
this.rawControls,
this.stateTrader,
this.customContextFromGates);
}
Expand Down
1 change: 1 addition & 0 deletions src/circuit/CircuitStats.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ class CircuitStats {
numWires,
Controls.NONE,
controlTex,
Controls.NONE,
stateTrader,
new Map()),
circuitDefinition,
Expand Down
36 changes: 29 additions & 7 deletions src/circuit/Controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,25 @@ class Controls {
/**
* @param {!int} inclusionMask.
* @param {!int} desiredValueMask
* @param {!int=0} parityMask
* @property {!int} inclusionMask.
* @property {!int} desiredValueMask
*/
constructor(inclusionMask, desiredValueMask) {
constructor(inclusionMask, desiredValueMask, parityMask=0) {
if ((desiredValueMask & ~inclusionMask) !== 0) {
throw new DetailedError("Desired un-included bits", {inclusionMask, desiredValueMask});
}
if (parityMask !== 0 && Util.popcnt(inclusionMask & parityMask) !== 1) {
throw new DetailedError("Exactly one parity bit must be in the inclusion mask",
{inclusionMask, parityMask});
}

/** @type {!int} */
this.inclusionMask = inclusionMask;
/** @type {!int} */
this.desiredValueMask = desiredValueMask;
/** @type {!int} */
this.parityMask = parityMask;
}

/**
Expand All @@ -57,7 +65,8 @@ class Controls {
isEqualTo(other) {
return other instanceof Controls &&
this.inclusionMask === other.inclusionMask &&
this.desiredValueMask === other.desiredValueMask;
this.desiredValueMask === other.desiredValueMask &&
this.parityMask === other.parityMask;
}

/**
Expand All @@ -68,12 +77,20 @@ class Controls {
return "No Controls";
}

return "Controls: ...__" + Seq.naturals().
takeWhile(i => (1<<i) <= this.inclusionMask).
map(this.desiredValueFor.bind(this)).
let range = Seq.naturals().takeWhile(i => (1<<i) <= (this.inclusionMask | this.parityMask));
let result = "Controls: ...__" + range.
map(e => this.desiredValueFor(e)).
map(e => e === undefined ? "_" : e ? "1" : "0").
reverse().
join("");
if (this.parityMask !== 0) {
result += "\n parity: ...__" + range.
map(e => this.parityMask & (1 << e)).
map(e => e ? "1" : "_").
reverse().
join("")
}
return result;
}

/**
Expand Down Expand Up @@ -113,9 +130,13 @@ class Controls {
if ((other.desiredValueMask & this.inclusionMask) !== (this.desiredValueMask & other.inclusionMask)) {
throw new DetailedError("Contradictory controls.", {"this": this, other})
}
if ((other.parityMask & this.inclusionMask) !== 0 || (this.parityMask & other.inclusionMask) !== 0) {
throw new DetailedError("Can't intersect parity controls.", {"this": this, other})
}
return new Controls(
this.inclusionMask | other.inclusionMask,
this.desiredValueMask | other.desiredValueMask);
this.desiredValueMask | other.desiredValueMask,
this.parityMask | other.parityMask);
}

/**
Expand All @@ -125,7 +146,8 @@ class Controls {
shift(offset) {
return new Controls(
this.inclusionMask << offset,
this.desiredValueMask << offset)
this.desiredValueMask << offset,
this.parityMask << offset)
}
}

Expand Down
Loading

0 comments on commit 1b9172b

Please sign in to comment.