Visualizing Quantum Annealing using WebGL simulator

Yuichiro Minato
May 19 · 3 min read

Introduction

We just introduced a simulator on quantum annealing using javascript. Now we try on WebGL to use our PC resources much more efficiently.

Implementation

This is simple we can visualizing a large image using webGL. We calculate Quantum Monte Carlo using javascript and separately webGL together. You can visualize a quite big image rather that javascript only.

<!doctype html>
<html><head>
    <style>
        body {
            font-size: 10px;
        }
    </style>
</head>
<script id="qbit_vs" type="x-shader/x-vertex">
    #version 300 es
    precision highp float;
    uniform int N;
    uniform int m;
    uniform float point_size;
    layout(location=0) in float state;
    layout(location=1) in float index;
    out vec4 vColor;
    void main() {
        // MEMO GL's 2D[-1:1], center of pixelは(0.5, 0.5)
        float x = (float(int(index) % N) + 0.5) / float(N) * 2.0 - 1.0;
        float y = (float(int(index) / N) + 0.5) / float(m) * 2.0 - 1.0;
        gl_Position = vec4(x, y, 0.0, 1.0);
        gl_PointSize = point_size;
        if(state > 0.0)
            vColor = vec4(1.0, 0.0, 0.0, 1.0);
        else
            vColor = vec4(0.0, 0.0, 1.0, 1.0);
    }
</script>
<script id="qbit_fs" type="x-shader/x-fragment">
    #version 300 es
    precision highp float;
    in vec4 vColor;
    out vec4 outColor;
    void main() {
        outColor = vColor;
    }
</script>
<body>
    G=<span id="GG"></span>
    <br><br>
    <canvas id="gl_canvas" width="150" height="50"></canvas>
    <script>
        //parameters
        const N = 1500
        const m = 750
        const kT = 0.0005
        const loop = 50000
        let G = 5 
        let q = new Float32Array(N * m)
        let jij = 1        const point_size = 1         let index = new Float32Array(N * m)
        for(let i = 0; i < N * m; i++)
            index[i] = i        //qbit initialize
        for(let i = 0; i < N * m; i++)
            q[i] = Math.floor(Math.random() - 0.5) * 2 + 1        // WebGL variables
        let gl_canvas, gl, qbit_vbo, index_vbo
        window.onload = function() {
            gl_canvas = document.getElementById('gl_canvas')
            gl = gl_canvas.getContext("webgl2")
            gl.clearColor(0.8, 0.8, 0.8, 1.0)
            gl.canvas.width = N * point_size
            gl.canvas.height = m * point_size
            index_vbo = createVbo(index)
            qbit_vbo = createDynamicVbo(q)
            draw_program = createProgram(document.getElementById('qbit_vs').text, document.getElementById('qbit_fs').text)
            update()
        }
        // main
        function update() {
            // calculate
            if (G < 0.001) {
                G = 5 
                for(let i = 0; i < N * m; i++)
                    q[i] = Math.floor(Math.random() - 0.5) * 2 + 1
            }
            anneal()
            // draw
            gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
            gl.clear(gl.COLOR_BUFFER_BIT)
            gl.useProgram(draw_program)
            gl.bindBuffer(gl.ARRAY_BUFFER, qbit_vbo) // VBOをBindして
            gl.bufferSubData(gl.ARRAY_BUFFER, 0, q) // 更新
            gl.uniform1i(gl.getUniformLocation(draw_program, 'N'), N)
            gl.uniform1i(gl.getUniformLocation(draw_program, 'm'), m)
            gl.uniform1f(gl.getUniformLocation(draw_program, 'point_size'), point_size)
            setAttribute(qbit_vbo, 0, 1)
            setAttribute(index_vbo, 1, 1)
            gl.drawArrays(gl.POINTS, 0, N * m)            window.requestAnimationFrame(update)
        }        function anneal() {
            //monte carlo loop start
            for (var k = 0; k < loop; k++) {
                const y = Math.floor(Math.random() * m) //select random trotter
                const x = Math.floor(Math.random() * N) //select random qbit
                //Energy difference calc
                let dE = (jij * 2 * q[y*N + x] * q[y*N + (N + x - 1) % N] + jij * 2 * q[y*N + x] * q[y*N + (x + 1) % N]) / m
                const kk = G / kT / m
                const kk1 = Math.exp(kk)
                const kk2 = Math.exp(-kk)
                //Quantum flactuation calc
                dE += q[y*N + x] * (q[((m + y - 1) % m)*N + x]
                    + q[((y + 1) % m)*N + x]) * Math.log((kk1 + kk2) / (kk1 - kk2)) / kT
                if (dE < 0 || Math.exp(-dE / kT) > Math.random()) // Metropolis
                    q[y*N + x] = -q[y*N + x] //flipping qbit
            }
            G *= 0.99
            document.getElementById('GG').innerHTML = G
        }        // WebGL functions
        function setAttribute(vbo, attrib_loc, stride) {
            gl.enableVertexAttribArray(attrib_loc)
            gl.bindBuffer(gl.ARRAY_BUFFER, vbo)
            gl.vertexAttribPointer(attrib_loc, stride, gl.FLOAT, false, 0, 0)
            gl.bindBuffer(gl.ARRAY_BUFFER, null)
        }        function compileShader(prog, src, type) {
            const sh = gl.createShader(type)
            gl.shaderSource(sh, src.replace(/^\n/, ""))
            gl.compileShader(sh)
            if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS))
                alert(gl.getShaderInfoLog(sh))
            gl.attachShader(prog, sh)
            gl.deleteShader(sh)
        }        function createProgram(vs, fs) {
            const program = gl.createProgram()
            compileShader(program, vs, gl.VERTEX_SHADER)
            compileShader(program, fs, gl.FRAGMENT_SHADER)
            gl.linkProgram(program)
            return program
        }        function createVbo(data) {
            const vbo = gl.createBuffer()
            gl.bindBuffer(gl.ARRAY_BUFFER, vbo)
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW)
            gl.bindBuffer(gl.ARRAY_BUFFER, null)
            return vbo
        }        function createDynamicVbo(data) {
            const vbo = gl.createBuffer()
            gl.bindBuffer(gl.ARRAY_BUFFER, vbo)
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.DYNAMIC_DRAW)
            gl.bindBuffer(gl.ARRAY_BUFFER, null)
            return vbo
        }
    </script>
</body></html>

Recently we can use many web technologies like webGL or webGPU. It is available without any setting up environment which is bothering many times.

Yuichiro Minato

Written by

MDR, Quantum Computing@Tokyo, https://mdrft.com/