Visualizing Quantum Annealing using WebGL simulator

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.