Skip to content

Commit

Permalink
Cuquantum backend (#84)
Browse files Browse the repository at this point in the history
* Add Docker of cuStatevector version (WIP)

* Small fixes

* update Dockerfile

* Now use qsim as the backend. Looks like cuquantum is too primitive at the moment
and cannot install outside of conda.

* WIP: cannot install cuQuantum at the moment

* .

* a small fix and now cuquantum builds.

* Cleanups.

* qsim_nvidia -> cirq

* fix cuQuantum download url

* add pycall for gem

* move

* .

* avoid the following error:
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

* test circuit

* .

* Update qni-cirqbridge.

* qsim GPU support requires to build from the source

* Updated cirqbridge. qsimcirq now runs on the GPU.

* Remove empty circuits.

* .

* .

* rename to cirq to cirq_backend

* Solve conflicts when merging from upstream

* Solve conflicts when merging from upstream

* back to my backend.

* .

* backout to my cirqbridge.

* .

* Impliment |0>, |1> initializations and H gate.

Co-authored-by: Yasuhito Takamiya <yasuhito@hey.com>
  • Loading branch information
nakatamaho and yasuhito authored Feb 14, 2022
1 parent bdea060 commit 7c5350d
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 5 deletions.
101 changes: 101 additions & 0 deletions Dockerfile_cirq_backend
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# 1. The Qniapp is built as follows:
# $ git clone https://github.com/qniapp/qni.git
# $ cd qni
# $ docker build -f Dockerfile_cirq_backend . -t qni_cirq_backend
# 2. Then run by:
# $ docker run -p 3000:3000 --gpus all --rm -it qni_cirq_backend
# 3. access http://127.0.0.1:3000 in your browser

# Troubleshooting
# If the port 3000 is already used, change 3000 to 4000 (for example)
# $ docker run -p 4000:3000 --gpus all --rm -it qni_cirq_backend
# and access http://127.0.0.1:4000 in your browser

FROM nvidia/cuda:11.5.1-devel-ubuntu20.04

RUN apt update
RUN apt -y upgrade
RUN apt install -y sudo
ENV DEBIAN_FRONTEND=noninteractive
RUN apt install -y tzdata
# set your timezone
ENV TZ Asia/Tokyo
RUN echo "${TZ}" > /etc/timezone \
&& rm /etc/localtime \
&& ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& dpkg-reconfigure -f noninteractive tzdata

RUN apt install -y build-essential
RUN apt install -y git wget time curl libssl-dev zlib1g-dev libpq-dev
RUN apt install -y redis-server
RUN apt install -y ng-common ng-cjk emacs-nox
RUN apt install -y postgresql postgresql-contrib

## cuda
RUN apt -y install cuda-drivers
RUN wget https://developer.download.nvidia.com/compute/cuquantum/redist/cuquantum/linux-x86_64/cuquantum-linux-x86_64-0.1.0.30-archive.tar.xz
RUN tar xvfJ cuquantum-linux-x86_64-0.1.0.30-archive.tar.xz -C /tmp
RUN cd /tmp/cuquantum-linux-x86_64-0.1.0.30-archive ; tar cf - . | (cd /usr/local; tar vxf -)

## node.js
RUN apt install -y nodejs npm && npm install n -g && n stable && apt purge -y nodejs npm

## npm
RUN curl -qL https://www.npmjs.com/install.sh | sh

## yarn
RUN npm install -g yarn

## ruby
RUN wget https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.4.tar.gz && tar xvfz ruby-2.7.4.tar.gz && cd ruby-2.7.4 && ./configure && make && make install

## python3
RUN apt install -y python3 python3-pip
RUN sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 1

ARG DOCKER_UID=1000
ARG DOCKER_USER=docker
ARG DOCKER_PASSWORD=docker
RUN useradd -u $DOCKER_UID -m $DOCKER_USER --shell /bin/bash && echo "$DOCKER_USER:$DOCKER_PASSWORD" | chpasswd && echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

USER ${DOCKER_USER}
RUN echo "\n\
[user]\n\
email = ${GIT_EMAIL}\n\
name = ${GIT_NAME}\n\
" > /home/$DOCKER_USER/.gitconfig

SHELL ["/bin/bash", "-l", "-c"]

# qsim
ENV PATH=/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/$DOCKER_USER/.rbenv/bin:/home/$DOCKER_USER/.local/bin
# for qsimcirq
ENV CUQUANTUM_DIR=/usr/local
RUN cd /home/$DOCKER_USER && pip3 install pybind11 pytest numpy sympy cirq
RUN cd /home/$DOCKER_USER && git clone https://github.com/quantumlib/qsim.git && cd qsim && make # && make run-py-tests # to use gpu qsim must be build locally

RUN cd /home/$DOCKER_USER && echo "cd /home/$DOCKER_USER" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && git clone https://github.com/rbenv/rbenv.git ~/.rbenv
RUN cd /home/$DOCKER_USER && git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
RUN cd /home/$DOCKER_USER && echo "export PATH=$PATH:$HOME/.rbenv/bin" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && echo "export CUQUANTUM_DIR=/usr/local" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && echo "export LD_LIBRARY_PATH=${CUQUANTUM_DIR}/lib64:${LD_LIBRARY_PATH}" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && git clone https://github.com/nakatamaho/qni.git
RUN cd /home/$DOCKER_USER && cd qni && git fetch origin cuquantum-backend
RUN cd /home/$DOCKER_USER && cd qni && git checkout cuquantum-backend

## settings for rails
RUN cd /home/$DOCKER_USER && cd qni/apps/www && bundle config set path 'vendor/cache' && bundle install && yarn install
RUN cd /home/$DOCKER_USER && cd qni && yarn build && cd apps/www && ./bin/rails css:build && ./bin/rails javascript:build

## settings for postgresql
RUN sudo -u postgres service postgresql start && sudo -u postgres psql --command "CREATE USER docker WITH SUPERUSER PASSWORD 'docker';" && sudo -u postgres createdb -O docker docker
RUN cd /home/$DOCKER_USER && sudo -u postgres service postgresql start && cd qni/apps/www && ./bin/rails db:create && ./bin/rails db:migrate && ./bin/rails db:fixtures:load

RUN cd /home/$DOCKER_USER && echo -e "#!/usr/bin/env bash\n\
export PYTHONPATH=/home/docker/qsim/ \n\
sudo -u postgres service postgresql start \n\
cd /home/${DOCKER_USER} ; source ~/.bashrc ; cd qni/apps/www \n\
./bin/rails s -b 0.0.0.0" > /tmp/startup.sh
RUN chmod 744 /tmp/startup.sh
#ENTRYPOINT ["/bin/sh", "-c", "/tmp/startup.sh"]
105 changes: 105 additions & 0 deletions Dockerfile_cuquantum
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# 1. The Qniapp is built as follows:
# $ git clone https://github.com/qniapp/qni.git
# $ cd qni
# $ docker build -f Dockerfile_cuquantum . -t qni_cuquantum
# 2. Then run by:
# $ docker run -p 3000:3000 --gpus all --rm -it qni_cuquantum
# 3. access http://127.0.0.1:3000 in your browser

# Troubleshooting
# If the port 3000 is already used, change 3000 to 4000 (for example)
# $ docker run -p 4000:3000 --gpus all --rm -it qni_cuquantum
# and access http://127.0.0.1:4000 in your browser

FROM nvidia/cuda:11.5.1-devel-ubuntu20.04

RUN apt update
RUN apt -y upgrade
RUN apt install -y sudo
ENV DEBIAN_FRONTEND=noninteractive
RUN apt install -y tzdata
# set your timezone
ENV TZ Asia/Tokyo
RUN echo "${TZ}" > /etc/timezone \
&& rm /etc/localtime \
&& ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& dpkg-reconfigure -f noninteractive tzdata

RUN apt install -y build-essential
RUN apt install -y git wget time curl libssl-dev zlib1g-dev libpq-dev
RUN apt install -y redis-server
RUN apt install -y ng-common ng-cjk emacs-nox
RUN apt install -y postgresql postgresql-contrib

## cuda
RUN apt -y install cuda-drivers
RUN apt -y install libcutensor1 libcutensor-dev libcutensor-doc
RUN wget https://developer.download.nvidia.com/compute/cuquantum/redist/cuquantum/linux-x86_64/cuquantum-linux-x86_64-0.1.0.30-archive.tar.xz
RUN tar xvfJ cuquantum-linux-x86_64-0.1.0.30-archive.tar.xz -C /tmp
RUN cd /tmp/cuquantum-linux-x86_64-0.1.0.30-archive ; tar cf - . | (cd /usr/local; tar vxf -)

## node.js
RUN apt install -y nodejs npm && npm install n -g && n stable && apt purge -y nodejs npm

## npm
RUN curl -qL https://www.npmjs.com/install.sh | sh

## yarn
RUN npm install -g yarn

## ruby
RUN wget https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.4.tar.gz && tar xvfz ruby-2.7.4.tar.gz && cd ruby-2.7.4 && ./configure && make && make install

## python3
RUN apt install -y python3 python3-pip
RUN sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 1

ARG DOCKER_UID=1000
ARG DOCKER_USER=docker
ARG DOCKER_PASSWORD=docker
RUN useradd -u $DOCKER_UID -m $DOCKER_USER --shell /bin/bash && echo "$DOCKER_USER:$DOCKER_PASSWORD" | chpasswd && echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

USER ${DOCKER_USER}
RUN echo "\n\
[user]\n\
email = ${GIT_EMAIL}\n\
name = ${GIT_NAME}\n\
" > /home/$DOCKER_USER/.gitconfig

SHELL ["/bin/bash", "-l", "-c"]

# cuQuantum
ENV CUQUANTUM_ROOT=/usr/local
ENV CUSTATEVEC_ROOT=/usr/local
ENV CUTENSOR_ROOT=/usr
ENV CUDA_PATH=/usr/local/cuda
ENV CUQUANTUM_IGNORE_SOLVER=1
RUN cd /home/$DOCKER_USER && pip3 install cupy-cuda115 numpy scipy cython
RUN cd /home/$DOCKER_USER && git clone https://github.com/NVIDIA/cuQuantum.git && cd cuQuantum/python && pip3 install -v .

# Qni
RUN cd /home/$DOCKER_USER && echo "cd /home/$DOCKER_USER" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && git clone https://github.com/rbenv/rbenv.git ~/.rbenv
RUN cd /home/$DOCKER_USER && git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
RUN cd /home/$DOCKER_USER && echo "export PATH=$PATH:$HOME/.rbenv/bin" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && echo "export CUQUANTUM_ROOT=/usr/local" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && echo "export LD_LIBRARY_PATH=${CUQUANTUM_ROOT}/lib64:${LD_LIBRARY_PATH}" >> ~/.bashrc
RUN cd /home/$DOCKER_USER && git clone https://github.com/nakatamaho/qni.git
RUN cd /home/$DOCKER_USER && cd qni && git fetch origin cuquantum-backend
RUN cd /home/$DOCKER_USER && cd qni && git checkout cuquantum-backend

## settings for rails
RUN cd /home/$DOCKER_USER && cd qni/apps/www && bundle config set path 'vendor/cache' && bundle install && yarn install
RUN cd /home/$DOCKER_USER && cd qni && yarn build && cd apps/www && ./bin/rails css:build && ./bin/rails javascript:build

## settings for postgresql
RUN sudo -u postgres service postgresql start && sudo -u postgres psql --command "CREATE USER docker WITH SUPERUSER PASSWORD 'docker';" && sudo -u postgres createdb -O docker docker
RUN cd /home/$DOCKER_USER && sudo -u postgres service postgresql start && cd qni/apps/www && ./bin/rails db:create && ./bin/rails db:migrate && ./bin/rails db:fixtures:load

RUN cd /home/$DOCKER_USER && echo -e "#!/usr/bin/env bash\n\
export PYTHONIOENCODING=utf-8 \n\
sudo -u postgres service postgresql start \n\
cd /home/${DOCKER_USER} ; source ~/.bashrc ; cd qni/apps/www \n\
./bin/rails s -b 0.0.0.0" > /tmp/startup.sh
RUN chmod 744 /tmp/startup.sh
ENTRYPOINT ["/bin/sh", "-c", "/tmp/startup.sh"]
1 change: 1 addition & 0 deletions apps/www/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ gem 'better_html'
gem 'bootsnap', '>= 1.4.2', require: false
gem 'grover'
gem 'serviceworker-rails'
gem 'pycall'

group :development, :test do
gem 'byebug', platforms: %i[mri mingw x64_mingw]
Expand Down
2 changes: 2 additions & 0 deletions apps/www/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ GEM
public_suffix (4.0.6)
puma (5.6.2)
nio4r (~> 2.0)
pycall (1.4.1)
racc (1.6.0)
rack (2.2.3)
rack-mini-profiler (2.3.3)
Expand Down Expand Up @@ -297,6 +298,7 @@ DEPENDENCIES
listen (>= 3.0.5, < 3.2)
pg
puma (~> 5.6)
pycall
rack-mini-profiler
rails (~> 6.1)
rbtrace
Expand Down
103 changes: 98 additions & 5 deletions apps/www/lib/cirq.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,92 @@
require 'pycall/import'
include PyCall::Import

PyCall.exec(<<~PYTHON)
import cirq
import io,sys
import numpy as np
import qsimcirq
from sympy import *
from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application, convert_xor
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
class cirqbridge:
def __init__(self):
return
def run_simulation(self,numofqubits,_circuit_from_qni):
print("python cirqbridge start")
sys.stdout.flush()
transformations = (standard_transformations + (implicit_multiplication_application,) + (convert_xor,))
circuit_from_qni = []
for a in _circuit_from_qni:
if len(a) != 0:
circuit_from_qni.append(a)
print(circuit_from_qni)
sys.stdout.flush()
qubits = cirq.LineQubit.range(numofqubits)
c = cirq.Circuit()
i = 0
m = 0
measurement = []
for column_qni in circuit_from_qni:
print("circuit column", i, column_qni)
i = i + 1
j = 0
for circuit_qni in column_qni:
j = j + 1
print("procssing circit ...")
print(column_qni)
sys.stdout.flush()
if circuit_qni['type'] == u'H':
targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
if not "controls" in circuit_qni:
c.append([ cirq.H(index) for index in targetqubits] )
else:
controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
c.append([ cirq.ControlledOperation(controledqubits, cirq.H(index)) for index in targetqubits ])
elif circuit_qni['type'] == u'|0>':
targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
c.append([ cirq.ops.reset(index) for index in targetqubits] )
elif circuit_qni['type'] == u'|1>':
targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
c.append([ cirq.ops.reset(index) for index in targetqubits] )
c.append([ cirq.X(index) for index in targetqubits] )
elif circuit_qni['type'] == u'':
pass #nop
else:
print("unsupported gate", circuit_qni['type'])
print("circuit column", column_qni)
print("")
print('Cirq circiut')
print(c)
cirq_simulator = cirq.Simulator()
cirq_result = cirq_simulator.simulate(c)
print('Cirq result:')
print(cirq_result)
sys.stdout.flush()
qsim_simulator = qsimcirq.QSimSimulator()
qsim_result = qsim_simulator.simulate(c)
print('qsim result:')
print(qsim_result)
sys.stdout.flush()
gpu_options = qsimcirq.QSimOptions(use_gpu=True)
qsim_simulator = qsimcirq.QSimSimulator(qsim_options=gpu_options)
qsim_gpu_result = qsim_simulator.simulate(c)
print('qsim GPU result:')
print(qsim_gpu_result)
sys.stdout.flush()
print("")
print("python cirqbridge end")
sys.stdout.flush()
#return (result.final_state_vector)
PYTHON

class Cirq
def initialize(circuit_id:, qubit_count:, step_index:, steps:, targets:)
@circuit_id = circuit_id
Expand All @@ -8,6 +97,8 @@ def initialize(circuit_id:, qubit_count:, step_index:, steps:, targets:)
end

def run
cirqbridge = PyCall.eval('cirqbridge').call
cirqbridge.run_simulation(@qubit_count, @steps)
@steps.map.with_index { |each, index| execute_step each, index }
end

Expand All @@ -31,8 +122,8 @@ def execute_step(step, index)
# {"type"=>"Z", "controls"=>[], "if"=>nil}
when 'P'
# {"type"=>"P", "phi"=>"pi/2", "controls"=>[], "targets"=>[0], "if"=>nil}
when 'X^½'
# {"type"=>"X^½", "controls"=>[], "if"=>nil}
when 'X^'
# {"type"=>"X^", "controls"=>[], "if"=>nil}
when 'Rx'
# {"type"=>"Rx", "theta"=>"pi/2", "controls"=>[], "targets"=>[], "if"=>nil}
when 'Ry'
Expand All @@ -41,16 +132,18 @@ def execute_step(step, index)
# {"type"=>"Rz", "theta"=>"pi/2", "controls"=>[], "targets"=>[], "if"=>nil}
when 'Swap'
# {"type"=>"Swap", "controls"=>[], "targets"=>[]}
when ''
# {"type"=>"", "targets"=>[0]}
when ''
# {"type"=>"", "targets"=>[0]}
when 'Bloch'
# {"type"=>"Bloch"}
when 'Write'
# {"type"=>"Write", "value"=>0}
when 'Measure'
# {"type"=>"Measure", "flag"=>""}
measured_bits[bit] = [0, 1].sample # rubocop:disable Performance/CollectionLiteralInLoop
when '1'
when '|0>'
# NOP
when '|1>'
# NOP
else
raise "Unknown operation: #{each.inspect}"
Expand Down

0 comments on commit 7c5350d

Please sign in to comment.