setActualEffectToShaderProvider(ctx => MODULAR_MULTIPLY_ACCUMULATE_SHADER.withArgs( ...ketArgs(ctx, span, ['A', 'B', 'R']), WglArg.float("factor", -1))).
setActualEffectToShaderProvider(ctx => X_TO_A_SHADER.withArgs( ...ketArgs(ctx, 1, ['A']), WglArg.float('factor', -Math.PI))).
let ModularMultiplyAccumulateGates = {}; const MODULAR_MULTIPLY_ACCUMULATE_SHADER = ketShaderPermute( ` uniform float factor; ${ketInputGateShaderCode('A')} ${ketInputGateShaderCode('B')} ${ketInputGateShaderCode('R')} ${BIG_MUL_MOD_SHADER_CODE} `, ` float r = read_input_R(); float a = read_input_A(); float b = read_input_B(); float d = big_mul_mod(factor * a, b, r); float in_id = floor(mod(out_id - d + 0.5, r)); if (in_id < 0.0) { in_id += r; } if (in_id >= r) { in_id -= r; } return out_id >= r ? out_id : in_id; `); ModularMultiplyAccumulateGates.PlusABModRFamily = Gate.buildFamily(1, 16, (span, builder) => builder. setSerializedId("+ABmodR" + span).
CircuitShaders.swap = (ctx, otherRow) => SWAP_QUBITS_SHADER.withArgs(...ketArgs(ctx, otherRow - ctx.row + 1));
let v = args.getGateContext('Input Range A'); let denom_exponent = v === undefined ? 'ⁿ' : Util.digits_to_superscript_digits('' + v.length); let symbol = args.gate.symbol.replace('ⁿ', denom_exponent); GatePainting.paintBackground(args); GatePainting.paintOutline(args); GatePainting.paintGateSymbol(args, symbol); } const X_TO_A_SHADER = ketShader( ` uniform float factor; ${ketInputGateShaderCode('A')} `, ` float angle = read_input_A() * factor / _gen_input_span_A; float c = cos(angle) * 0.5; float s = sin(angle) * 0.5; vec2 u = vec2(0.5 + c, s); vec2 v = vec2(0.5 - c, -s); // multiply state by the matrix [[u, v], [v, u]] vec2 amp2 = inp(1.0-out_id); return cmul(u, amp) + cmul(v, amp2); `); const Y_TO_A_SHADER = ketShader( ` uniform float factor; ${ketInputGateShaderCode('A')} `, ` float angle = read_input_A() * factor / _gen_input_span_A;
ctx => PHASE_GRADIENT_SHADER.withArgs(...ketArgs(ctx, 4), WglArg.float('factor', -Math.PI/16)),
vec2 outputFor(float k) { return read_input(scatter(k)); }`); /** * Renders the result of applying a controlled swap operation to a superposition. * * @param {!CircuitEvalContext} ctx * @param {!int} otherRow * @returns {!WglConfiguredShader} */ CircuitShaders.swap = (ctx, otherRow) => SWAP_QUBITS_SHADER.withArgs(...ketArgs(ctx, otherRow - ctx.row + 1)); const SWAP_QUBITS_SHADER = ketShaderPermute('', ` float low_bit = mod(out_id, 2.0); float mid_bits = floor(mod(out_id, span*0.5)*0.5); float high_bit = floor(out_id*2.0/span); return high_bit + mid_bits*2.0 + low_bit*span*0.5;`); /** * Returns a configured shader that renders the marginal states of each qubit, for each possible values of the other * qubits (i.e. folding still needs to be done), into a destination texture. The marginal states are laid out in * [a,br,bi,d] order within each pixel and represent the density matrix {{a, b},{b*, d}}. * @param {!WglTexture} inputTexture A superposition texture. * @param {undefined|!int=} keptBitMask A bit mask with a 1 at the positions corresponding to indicates of the desired * qubit densities. * @returns {!WglConfiguredShader} */ CircuitShaders.qubitDensities = (inputTexture, keptBitMask = undefined) => { if (keptBitMask === undefined) { keptBitMask = (1 << currentShaderCoder().vec2.arrayPowerSizeOfTexture(inputTexture)) - 1;
import {Config} from "src/Config.js" import {Gate} from "src/circuit/Gate.js" import {ketArgs, ketShaderPermute, ketInputGateShaderCode} from "src/circuit/KetShaderUtil.js" import {Util} from "src/base/Util.js" import {WglArg} from "src/webgl/WglArg.js" let BitCountGates = {}; const POP_COUNT_SHADER = ketShaderPermute( ` uniform float factor; ${ketInputGateShaderCode('A')} `, ` float d = read_input_A(); float popcnt = 0.0; for (int i = 0; i < ${Config.MAX_WIRE_COUNT}; i++) { popcnt += mod(d, 2.0); d = floor(d / 2.0); } float offset = mod(popcnt * factor, span); return mod(out_id + span - offset, span);`); BitCountGates.PlusBitCountAFamily = Gate.buildFamily(1, 16, (span, builder) => builder. setSerializedIdAndSymbol("+cntA" + span). setSymbol("+1s(A)"). setTitle("Bit Count Gate"). setBlurb("Counts the number of ON bits in input A and adds that into this output."). setRequiredContextKeys("Input Range A"). setActualEffectToShaderProvider(ctx => POP_COUNT_SHADER.withArgs( ...ketArgs(ctx, span, ['A']),
setActualEffectToShaderProvider(ctx => POP_COUNT_SHADER.withArgs( ...ketArgs(ctx, span, ['A']), WglArg.float("factor", -1))).
let universalNot = ctx => UNIVERSAL_NOT_SHADER.withArgs(...ketArgs(ctx));
// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import {GateBuilder} from "src/circuit/Gate.js" import {ketArgs, ketShader} from "src/circuit/KetShaderUtil.js" import {WglConfiguredShader} from "src/webgl/WglConfiguredShader.js" /** * @param {!CircuitEvalContext} ctx * @returns {!WglConfiguredShader} */ let universalNot = ctx => UNIVERSAL_NOT_SHADER.withArgs(...ketArgs(ctx)); const UNIVERSAL_NOT_SHADER = ketShader( '', 'vec2 other = inp(1.0 - out_id); return vec2(other.x, -other.y) * (1.0 - 2.0 * out_id);', 1); let UniversalNotGate = new GateBuilder(). setSerializedId("__unstable__UniversalNot"). setSymbol("UniNot"). setTitle("Universal Not Gate"). setBlurb("Mirrors through the origin of the Bloch sphere.\nImpossible in practice."). setActualEffectToShaderProvider(universalNot). promiseEffectIsStable(). gate; export {universalNot, UniversalNotGate}
r = floor(mod(f + 0.5, ${1<<MUL_STEP}.0)); f -= r; t = floor(mod(t + b*r + 0.5, modulus)); b = floor(mod(b * ${1<<MUL_STEP}.0 + 0.5, modulus)); f /= ${1<<MUL_STEP}.0; } return t; } `; const MULTIPLY_ACCUMULATE_SHADER = ketShaderPermute( ` uniform float factor; ${ketInputGateShaderCode('A')} ${ketInputGateShaderCode('B')} ${BIG_MUL_MOD_SHADER_CODE} `, ` float d1 = read_input_A(); float d2 = read_input_B(); float d = floor(mod(big_mul_mod(d1, d2, span)*factor + 0.5, span)); return mod(out_id + span - d, span);`); MultiplyAccumulateGates.Legacy_MultiplyAddFamily = Gate.buildFamily(3, 16, (span, builder) => builder. setSerializedId("c+=ab" + span). setSymbol("c+=ab"). setTitle("Multiply-Add Gate"). setBlurb("Adds the product of two numbers into a third."). setDrawer(GatePainting.SECTIONED_DRAWER_MAKER( ["a", "b", "c+=ab"], sectionSizes(span).slice(0, 2).map(e => e/span))). setActualEffectToUpdateFunc(ctx => {
setActualEffectToShaderProvider(ctx => ADDITION_SHADER.withArgs( ...ketArgs(ctx, span, ['A']), WglArg.float("factor", +1))).
const chunkedScaledAdditionPermutationMaker = (span, factor) => e => { let sa = Math.floor(span/2); let sb = Math.ceil(span/2); let a = e & ((1 << sa) - 1); let b = e >> sa; b += a * factor; b &= ((1 << sb) - 1); return a + (b << sa); }; const ADDITION_SHADER = ketShaderPermute( ` uniform float factor; ${ketInputGateShaderCode('A')} `, ` float d = read_input_A(); d *= factor; d = mod(d, span); return mod(out_id + span - d, span);`); ArithmeticGates.Legacy_AdditionFamily = Gate.buildFamily(2, 16, (span, builder) => builder. setSerializedId("add" + span). setSymbol("b+=a"). setTitle("Addition Gate"). setBlurb("Adds a little-endian number into another."). setDrawer(GatePainting.SECTIONED_DRAWER_MAKER(["a", "b+=a"], [Math.floor(span/2) / span])). setActualEffectToUpdateFunc(ctx => ArithmeticGates.PlusAFamily.ofSize(Math.ceil(span/2)).customOperation( ctx.withRow(ctx.row + Math.floor(span/2)). withInputSetToRange('A', ctx.row, Math.floor(span/2)))).