diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9fa470c50..1078edc0c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -55,6 +55,14 @@ jobs:
POSTGRES_PASSWORD: postgres
- run: lerna bootstrap
- run: yarn build
+ - name: javascript:build
+ run: |-
+ cd apps/www
+ bundle exec rails javascript:build
+ - name: css:build
+ run: |-
+ cd apps/www
+ bundle exec rails css:build
- run: yarn test:ci
env:
RAILS_ENV: test
diff --git a/Dockerfile_cirq_backend b/Dockerfile_cirq_backend
new file mode 100644
index 000000000..017d79621
--- /dev/null
+++ b/Dockerfile_cirq_backend
@@ -0,0 +1,106 @@
+# 1. The Qniapp is built as follows:
+# $ git clone https://github.com/qniapp/qni.git
+# $ cd qni
+# $ git fetch origin cirq-backend
+# $ git checkout cirq-backend
+# $ 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-22.03.0.40-archive.tar.xz
+RUN tar xvfJ cuquantum-linux-x86_64-22.03.0.40-archive.tar.xz -C /tmp
+RUN cd /tmp/cuquantum-linux-x86_64-22.03.0.40-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 LANG=C.UTF-8" >> ~/.bashrc
+RUN cd /home/$DOCKER_USER && echo "export LC_CTYPE=C.UTF-8" >> ~/.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/qniapp/qni.git
+RUN cd /home/$DOCKER_USER && cd qni && git fetch origin cirq-backend
+RUN cd /home/$DOCKER_USER && cd qni && git checkout cirq-backend
+RUN cd /home/$DOCKER_USER && cd qni && git log -1
+
+## 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"]
diff --git a/Dockerfile_cuquantum b/Dockerfile_cuquantum
new file mode 100644
index 000000000..708589d1b
--- /dev/null
+++ b/Dockerfile_cuquantum
@@ -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-22.03.0.40-archive.tar.xz
+RUN tar xvfJ cuquantum-linux-x86_64-22.03.0.40-archive.tar.xz -C /tmp
+RUN cd /tmp/cuquantum-linux-x86_64-22.03.0.40-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"]
diff --git a/apps/www/Gemfile b/apps/www/Gemfile
index 1db9c550d..51aa85980 100644
--- a/apps/www/Gemfile
+++ b/apps/www/Gemfile
@@ -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]
diff --git a/apps/www/Gemfile.lock b/apps/www/Gemfile.lock
index b5e387cd5..6effa219e 100644
--- a/apps/www/Gemfile.lock
+++ b/apps/www/Gemfile.lock
@@ -165,6 +165,7 @@ GEM
public_suffix (4.0.6)
puma (5.6.4)
nio4r (~> 2.0)
+ pycall (1.4.1)
racc (1.6.0)
rack (2.2.3)
rack-mini-profiler (2.3.3)
@@ -297,6 +298,7 @@ DEPENDENCIES
listen (>= 3.0.5, < 3.2)
pg
puma (~> 5.6)
+ pycall
rack-mini-profiler
rails (~> 6.1)
rbtrace
diff --git a/apps/www/app/assets/javascripts/serviceworker.js b/apps/www/app/assets/javascripts/serviceworker.js
index 3fb6201ca..97941b585 100644
--- a/apps/www/app/assets/javascripts/serviceworker.js
+++ b/apps/www/app/assets/javascripts/serviceworker.js
@@ -9,26 +9,77 @@ self.addEventListener(
const steps = e.data.steps
const targets = e.data.targets
const simulator = new Simulator('0'.repeat(qubitCount))
+ const backend = e.data.backend
Util.notNull(qubitCount)
Util.notNull(stepIndex)
Util.notNull(steps)
Util.notNull(targets)
- steps.forEach((operations, i) => {
- simulator.runStep(operations)
-
- self.postMessage({
- type: 'step',
- step: i,
- amplitudes: i === stepIndex ? simulator.amplitudes(targets) : [],
- blochVectors: simulator.blochVectors,
- measuredBits: simulator.measuredBits,
- flags: simulator.flags
- })
- })
+ if (backend) {
+ const json = e.data.json
+ Util.notNull(json)
+
+ runBackend(json, qubitCount, stepIndex, steps, targets, backend)
+ } else {
+ runQniSimulator(qubitCount, stepIndex, steps, targets)
+ }
self.postMessage({type: 'finish'})
},
false
)
+
+function runQniSimulator(qubitCount, stepIndex, steps, targets) {
+ const simulator = new Simulator('0'.repeat(qubitCount))
+
+ steps.forEach((operations, i) => {
+ simulator.runStep(operations)
+
+ self.postMessage({
+ type: 'step',
+ step: i,
+ amplitudes: i === stepIndex ? simulator.amplitudes(targets) : {},
+ blochVectors: simulator.blochVectors,
+ measuredBits: simulator.measuredBits,
+ flags: simulator.flags
+ })
+ })
+}
+
+function runBackend(json, qubitCount, stepIndex, steps, targets, backend) {
+ const params = new URLSearchParams({
+ id: json,
+ qubitCount: qubitCount,
+ stepIndex: stepIndex,
+ steps: JSON.stringify(steps),
+ targets: targets,
+ backend: backend
+ })
+
+ fetch(`/backend.json?${params}`, {
+ method: 'GET'
+ })
+ .then(response => {
+ if (!response.ok) {
+ throw new Error("Failed to connect to Qni's backend endpoint.")
+ }
+ return response.json()
+ })
+ .then(response => {
+ for (let i = 0; i < response.length; i++) {
+ const stepResult = response[i]
+ self.postMessage({
+ type: 'step',
+ step: i,
+ amplitudes: stepResult['amplitudes'],
+ blochVectors: stepResult['blochVectors'],
+ measuredBits: stepResult['measuredBits'],
+ flags: {}
+ })
+ }
+ })
+ .catch(error => {
+ console.error(error)
+ })
+}
diff --git a/apps/www/app/controllers/backend_controller.rb b/apps/www/app/controllers/backend_controller.rb
new file mode 100644
index 000000000..73a588e7a
--- /dev/null
+++ b/apps/www/app/controllers/backend_controller.rb
@@ -0,0 +1,20 @@
+require 'cirq'
+
+class BackendController < ApplicationController
+ # rubocop:disable Metrics/AbcSize
+ def show
+ backend = params[:backend]
+ circuit_id = params[:id]
+ qubit_count = params[:qubitCount].to_i
+ step_index = params[:stepIndex].to_i
+ steps = params[:steps] ? JSON.parse(params[:steps]) : []
+ targets = params[:targets].split(',').map(&:to_i) if params[:targets]
+
+ raise "Unsupported backend: #{backend}" unless backend == 'cirq'
+
+ @step_results =
+ Cirq.new(circuit_id: circuit_id, qubit_count: qubit_count, step_index: step_index, steps: steps, targets: targets)
+ .run
+ end
+ # rubocop:enable Metrics/AbcSize
+end
diff --git a/apps/www/app/controllers/cirq_controller.rb b/apps/www/app/controllers/cirq_controller.rb
new file mode 100644
index 000000000..0a177cb8e
--- /dev/null
+++ b/apps/www/app/controllers/cirq_controller.rb
@@ -0,0 +1,3 @@
+class CirqController < ApplicationController
+ def show; end
+end
diff --git a/apps/www/app/models/concerns/routing.rb b/apps/www/app/models/concerns/routing.rb
index 1ec9745d8..efdac9ba8 100644
--- a/apps/www/app/models/concerns/routing.rb
+++ b/apps/www/app/models/concerns/routing.rb
@@ -3,15 +3,9 @@
module Routing
extend ActiveSupport::Concern
- included do
- include Rails.application.routes.url_helpers
- end
+ included { include Rails.application.routes.url_helpers }
def default_url_options
- if Rails.env.production?
- { host: 'qniapp.net' }
- else
- { host: 'localhost', port: 3000 }
- end
+ Rails.env.production? ? { host: 'qniapp.net' } : { host: 'localhost', port: 3000 }
end
end
diff --git a/apps/www/app/views/backend/show.json.jbuilder b/apps/www/app/views/backend/show.json.jbuilder
new file mode 100644
index 000000000..1b6944d1a
--- /dev/null
+++ b/apps/www/app/views/backend/show.json.jbuilder
@@ -0,0 +1 @@
+json.array! @step_results
diff --git a/apps/www/app/views/cirq/show.html.erb b/apps/www/app/views/cirq/show.html.erb
new file mode 100644
index 000000000..5c3a74407
--- /dev/null
+++ b/apps/www/app/views/cirq/show.html.erb
@@ -0,0 +1,201 @@
+<% content_for :meta_ogp do %>
+
+
+ <% if @json %>
+
+
+ <% end %>
+ <% if @circuit&.social_image&.attached? %>
+
+ <% end %>
+<% end %>
+
+
+
+<%= palette_help_templates %>
+
+
+
+
+
+
+
+
If Conditional
+
+
+
+
+
+
+
+
+
Angle
+
+
+
+
+
+
+
+
+
+ = nπ/?
+
+
+
+
+
+
+
+
+
+
+
+
+
Conditional Flag
+
+
+
+
+
+
+
+
+
diff --git a/apps/www/config/environments/production.rb b/apps/www/config/environments/production.rb
index 30e69d127..adc0fe1e9 100644
--- a/apps/www/config/environments/production.rb
+++ b/apps/www/config/environments/production.rb
@@ -11,7 +11,7 @@
config.eager_load = true
# Full error reports are disabled and caching is turned on.
- config.consider_all_requests_local = false
+ config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
@@ -66,9 +66,9 @@
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV['RAILS_LOG_TO_STDOUT'].present?
- logger = ActiveSupport::Logger.new($stdout)
+ logger = ActiveSupport::Logger.new($stdout)
logger.formatter = config.log_formatter
- config.logger = ActiveSupport::TaggedLogging.new(logger)
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
diff --git a/apps/www/config/routes.rb b/apps/www/config/routes.rb
index 0cd297706..8ed12f2e2 100644
--- a/apps/www/config/routes.rb
+++ b/apps/www/config/routes.rb
@@ -1,7 +1,12 @@
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
-Rails.application.routes.draw do
- resources :circuits, only: %i[index] if Rails.env.development?
+Rails
+ .application
+ .routes
+ .draw do
+ resources :circuits, only: %i[index] if Rails.env.development?
- get 'svg/(:json)', to: 'circuit_svg#show', as: :circuit_svg, constraints: { json: /.*/ }
- get '/(:json)', to: 'circuits#show', as: :circuit, constraints: { json: /.*/ }
-end
+ get '/backend', to: 'backend#show'
+ get '/cirq/(:json)', to: 'cirq#show', as: :cirq
+ get 'svg/(:json)', to: 'circuit_svg#show', as: :circuit_svg, constraints: { json: /.*/ }
+ get '/(:json)', to: 'circuits#show', as: :circuit, constraints: { json: /.*/ }
+ end
diff --git a/apps/www/lib/cirq.rb b/apps/www/lib/cirq.rb
new file mode 100644
index 000000000..b5d1ce6d2
--- /dev/null
+++ b/apps/www/lib/cirq.rb
@@ -0,0 +1,325 @@
+# coding: utf-8
+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')
+from cirq.circuits import InsertStrategy
+
+class cirqbridge:
+ def __init__(self):
+ return
+
+ def lookup_measurement_label(self,_circuit_from_qni,label):
+ numofdevices=0
+ print("measurement_label: lookup for ", label)
+ sys.stdout.flush()
+ print("_circuit", _circuit_from_qni)
+ sys.stdout.flush()
+ counter = 0
+ label_found = 0
+ for _i in _circuit_from_qni:
+ if label_found == 1:
+ break
+# print("_i, counter ", _i, counter)
+# sys.stdout.flush()
+ if _i == []:
+ continue
+ for _p in range(len(_i)):
+ if 'flag' in _i[_p]:
+ if _i[_p]['type'] == "Measure" and _i[_p]['flag'] != label:
+ counter = counter + 1
+ elif _i[_p]['type'] == "Measure" and _i[_p]['flag'] == label:
+ print("found flag _i[%d]" % _p, _i[_p]['flag'])
+ label_found = 1
+ break
+ sys.stdout.flush()
+ print("counter", counter)
+ label='m' + str(counter)
+ return label
+
+ def build_circuit(self,numofqubits,_circuit_from_qni):
+# print("build_circuit")
+# sys.stdout.flush()
+ transformations = (standard_transformations + (implicit_multiplication_application,) + (convert_xor,))
+ circuit_from_qni = []
+ for a in _circuit_from_qni:
+ circuit_from_qni.append(a)
+ sys.stdout.flush()
+ qubits = cirq.LineQubit.range(numofqubits)
+ c = cirq.Circuit()
+ m = 0
+ measurement_moment = []
+ _current_index = 0
+ for column_qni in circuit_from_qni:
+ print("circuit column", column_qni)
+ sys.stdout.flush()
+ moment = []
+ measurement_moment.append([])
+ if len(column_qni)==0: # null or invalid step is converted to I gate
+ _c = [cirq.I(qubits[0])]
+ moment.append(_c)
+ for circuit_qni in column_qni:
+ if circuit_qni['type'] == u'H':
+ if "if" in circuit_qni: # classical control
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ label=self.lookup_measurement_label(_circuit_from_qni, circuit_qni['if'])
+ _c=[cirq.H(index).with_classical_controls(label) for index in targetqubits]
+ else:
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c=[cirq.H(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c=[ cirq.ControlledOperation(controledqubits, cirq.H(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'X':
+ if "if" in circuit_qni: # classical control
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ label=self.lookup_measurement_label(_circuit_from_qni, circuit_qni['if'])
+ _c=[cirq.X(index).with_classical_controls(label) for index in targetqubits]
+ else:
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c=[ cirq.X(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c=[ cirq.ControlledOperation(controledqubits, cirq.X(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'Y':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c=[ cirq.Y(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c=[ cirq.ControlledOperation(controledqubits, cirq.Y(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'Z':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c=[cirq.Z(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c=[ cirq.ControlledOperation(controledqubits, cirq.Z(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'Rx':
+ _angle = circuit_qni['angle'].replace(u'π','pi')
+ expr = parse_expr(_angle, transformations=transformations)
+ angle = float(expr.evalf())
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c=[ cirq.rx(angle).on(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c=[ cirq.ControlledOperation(controledqubits, cirq.rx(angle).on(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'Ry':
+ _angle = circuit_qni['angle'].replace(u'π','pi')
+ expr = parse_expr(_angle, transformations=transformations)
+ angle = float(expr.evalf())
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c= [ cirq.ry(angle).on(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c =[ cirq.ControlledOperation(controledqubits, cirq.ry(angle).on(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'Rz':
+ _angle = circuit_qni['angle'].replace(u'π','pi')
+ expr = parse_expr(_angle, transformations=transformations)
+ angle = float(expr.evalf())
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c = [ cirq.rz(angle).on(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c = [ cirq.ControlledOperation(controledqubits, cirq.rz(angle).on(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'P':
+ _angle = circuit_qni['angle'].replace(u'π','pi') + '/ pi'
+ expr = parse_expr(_angle, transformations=transformations)
+ angle = float(expr.evalf())
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c = [ cirq.ZPowGate(exponent=angle).on(index) for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c = [ cirq.ControlledOperation(controledqubits, cirq.ZPowGate(exponent=angle).on(index)) for index in targetqubits ]
+ elif circuit_qni['type'] == u'T':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c = [ cirq.Z(index)**0.25 for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c = [ cirq.ControlledOperation(controledqubits, cirq.Z(index)**0.25) for index in targetqubits ]
+ elif circuit_qni['type'] == u'X^½':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if not "controls" in circuit_qni:
+ _c = [ cirq.X(index)**0.5 for index in targetqubits]
+ else:
+ controledqubits=[ qubits[index] for index in circuit_qni['controls'] ]
+ _c = [ cirq.ControlledOperation(controledqubits, cirq.X(index)**0.5) for index in targetqubits ]
+ elif circuit_qni['type'] == u'•':
+ if "controls" in circuit_qni:
+ print("control is not supported for CZ gate", circuit_qni['type'])
+ sys.stdout.flush()
+ exit(1)
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ if len(targetqubits) == 2:
+ _c = [ cirq.CZ(qubits[circuit_qni['targets'][0]], qubits[circuit_qni['targets'][1]]) ]
+ elif len(targetqubits) < 2:
+ print("the number of target qubits must be larger than 2")
+ sys.stdout.flush()
+ exit(1)
+ else:
+ # we regard the first and the second qubit as the target qubits,
+ # and others are controlled qubits.
+ controledqubits = []
+ for _i in range(len(circuit_qni['targets'])-2):
+ controledqubits.append(qubits[circuit_qni['targets'][_i+2]])
+ sys.stdout.flush()
+ _c = [ cirq.ControlledOperation(controledqubits, cirq.CZ(qubits[circuit_qni['targets'][0]], qubits[circuit_qni['targets'][1]])) ]
+ elif circuit_qni['type'] == u'|0>':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ _c = [ cirq.ops.reset(index) for index in targetqubits]
+ elif circuit_qni['type'] == u'|1>':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ _c = [ cirq.ops.reset(index) for index in targetqubits]
+ _c.append([ cirq.X(index) for index in targetqubits])
+ elif circuit_qni['type'] == u'Measure':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ _c = [ cirq.measure(targetqubits[index], key = 'm' + str(m + index)) for index in range(len(targetqubits))]
+ __m = [ 'm' + str(m + index) for index in range(len(targetqubits))]
+ _m = [[__m[index], circuit_qni['targets'][index]] for index in range(len(targetqubits))]
+ measurement_moment[_current_index].append(_m)
+ m = m + len(targetqubits)
+ elif circuit_qni['type'] == u'Swap':
+ targetqubit0=qubits[circuit_qni['targets'][0]]
+ targetqubit1=qubits[circuit_qni['targets'][1]]
+ _c = []
+ _c.append(cirq.SWAP(targetqubit0,targetqubit1))
+ elif circuit_qni['type'] == u'Bloch':
+ targetqubits=[ qubits[index] for index in circuit_qni['targets'] ]
+ _c = [ cirq.ops.I(index) for index in targetqubits] # add a dummy gate to count Bloch operation as a step
+ elif circuit_qni['type'] == u'':
+ pass #nop
+ else:
+ print("unsupported gate", circuit_qni['type'])
+ sys.stdout.flush()
+ exit(1)
+ for __c in _c:
+ moment.append(__c)
+ c.append(moment, strategy=InsertStrategy.NEW_THEN_INLINE)
+ _current_index = _current_index + 1
+# print(c)
+# sys.stdout.flush()
+ return c, measurement_moment
+
+ def run_circuit_until_step_index(self, c, measurement_moment, until, steps):
+ print("run_circuit_until_step_index")
+ print("circuit:")
+ print(c)
+ sys.stdout.flush()
+# print("until (corrected):", until)
+# sys.stdout.flush()
+# print("steps(len):", len(steps))
+# sys.stdout.flush()
+ print("steps:", steps)
+ sys.stdout.flush()
+ cirq_simulator = cirq.Simulator()
+ _data = []
+ counter = -1
+ sleep_flag = 0 # we need padding for |1> because implimented as R + X
+ for _counter, step in enumerate(cirq_simulator.simulate_moment_steps(c)):
+ if sleep_flag == 0:
+ counter = counter + 1
+ dic = {}
+ dic[':blochVectors']={}
+ dic[':measuredBits'] = {}
+ if sleep_flag == 0:
+ for _d in steps[counter]:
+ if 'type' in _d:
+ if _d['type'] == u'|1>':
+ sleep_flag = 1
+ else:
+ sleep_flag = 0
+ if sleep_flag == 1:
+ continue
+
+ print("current step[%d]" % counter, steps[counter])
+ sys.stdout.flush()
+ if steps[counter] == []:
+ pass
+ else:
+ bloch_index = -1
+ for _bloch_index in range(len(steps[counter])):
+ if steps[counter][_bloch_index]['type'] == 'Bloch':
+ bloch_index = _bloch_index
+# print("bloch_index ", bloch_index)
+# sys.stdout.flush()
+ if bloch_index != -1:
+ for _bloch_target in steps[counter][bloch_index]['targets']:
+ blochxyz=cirq.qis.bloch_vector_from_state_vector(step.state_vector(),_bloch_target)
+ dic[':blochVectors'][_bloch_target] = blochxyz
+ print("bloch sphere: ", blochxyz)
+ sys.stdout.flush()
+ if counter == until:
+ dic[':amplitude'] = step.state_vector()
+ print("amplitudes: ", step.state_vector())
+ sys.stdout.flush()
+ _data.append(dic)
+ if len(step.measurements) != 0:
+ for i in range(len(measurement_moment)):
+ if len(measurement_moment[i]) !=0:
+# print("searching key", measurement_moment[i])
+ for k in range(len(measurement_moment[i])):
+ for j in range(len(measurement_moment[i][k])):
+ _key = measurement_moment[i][k][j][0]
+ _qubit = measurement_moment[i][k][j][1]
+ _step = i
+ if _key not in step.measurements:
+ break
+ _value= step.measurements[_key][0]
+ print("step: ", _step, "key:", _key, "target qubit", _qubit, "value ", _value)
+ sys.stdout.flush()
+ _data[i][':measuredBits'][_qubit] = _value
+# print("_data ", _data)
+# sys.stdout.flush()
+ return _data
+
+PYTHON
+
+class Cirq
+ def initialize(circuit_id:, qubit_count:, step_index:, steps:, targets:)
+ @circuit_id = circuit_id
+ @qubit_count = qubit_count
+ @step_index = step_index
+ @steps = steps
+ @targets = targets
+ end
+
+ def run
+ cirqbridge = PyCall.eval('cirqbridge').call
+ cirq_circuit, measurement_moment = cirqbridge.build_circuit(@qubit_count, @steps)
+ _result_list = cirqbridge.run_circuit_until_step_index(cirq_circuit, measurement_moment, @step_index, @steps).to_a
+ result_list = []
+ for var in _result_list do
+ hash = {}
+ a = var.to_h
+ hash[:measuredBits]=a[":measuredBits"].to_h
+ hash[:blochVectors]={}
+ for b in a[":blochVectors"].to_h do
+ c = Array[b[1][0].to_f, b[1][1].to_f, b[1][2].to_f]
+ hash[:blochVectors][b[0]] = c
+ end
+ result_list.push(hash)
+ end
+ _amplitudes=_result_list[@step_index][':amplitude']
+ amplitudes = {}
+ for num in 0.._amplitudes.size-1 do
+ amplitudes.store(num,Array[_amplitudes[num].real.to_f,_amplitudes[num].imag.to_f])
+ end
+ result_list[@step_index][:amplitudes]=amplitudes
+ p result_list
+ result_list
+ end
+end
diff --git a/apps/www/test/controllers/backend_controller_test.rb b/apps/www/test/controllers/backend_controller_test.rb
new file mode 100644
index 000000000..87540d08c
--- /dev/null
+++ b/apps/www/test/controllers/backend_controller_test.rb
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class BackendControllerTest < ActionDispatch::IntegrationTest
+ test 'should get show' do
+ get backend_url(format: :json, backend: 'cirq')
+ assert_response :success
+ end
+end
diff --git a/apps/www/test/controllers/cirq_controller_test.rb b/apps/www/test/controllers/cirq_controller_test.rb
new file mode 100644
index 000000000..7534d7d35
--- /dev/null
+++ b/apps/www/test/controllers/cirq_controller_test.rb
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class CirqControllerTest < ActionDispatch::IntegrationTest
+ test 'should get show' do
+ get cirq_url
+ assert_response :success
+ end
+end
diff --git a/packages/elements/src/quantum-circuit-element.ts b/packages/elements/src/quantum-circuit-element.ts
index 415500117..9d7f1398e 100644
--- a/packages/elements/src/quantum-circuit-element.ts
+++ b/packages/elements/src/quantum-circuit-element.ts
@@ -1257,7 +1257,8 @@ export class QuantumCircuitElement extends HoverableMixin(HTMLElement) {
}
private get urlJson(): string {
- const json = window.location.href.toString().split(window.location.host)[1].slice(1)
+ const json = window.location.href.toString().split('/').pop()
+ Util.notNull(json)
return decodeURIComponent(json)
}
diff --git a/packages/elements/src/quantum-simulator-element.ts b/packages/elements/src/quantum-simulator-element.ts
index 25211dd0c..afbc82ccb 100644
--- a/packages/elements/src/quantum-simulator-element.ts
+++ b/packages/elements/src/quantum-simulator-element.ts
@@ -17,6 +17,7 @@ type MessageEventData = {
}
export class QuantumSimulatorElement extends HTMLElement {
+ @attr backend = ''
@attr updateUrl = false
@target circuit!: QuantumCircuitElement
@@ -28,7 +29,7 @@ export class QuantumSimulatorElement extends HTMLElement {
declare worker: Worker
connectedCallback(): void {
- this.worker = new Worker('./serviceworker.js')
+ this.worker = new Worker('/serviceworker.js')
this.visibleQubitCircleKets = []
this.worker.addEventListener('message', this.handleServiceWorkerMessage.bind(this))
@@ -145,11 +146,14 @@ export class QuantumSimulatorElement extends HTMLElement {
const qubitCount = maxControlTargetBit >= 0 ? maxControlTargetBit + 1 : 1
this.circleNotation.qubitCount = qubitCount
+ const backend = this.backend.trim()
this.worker.postMessage({
+ json: this.circuit.toJson(),
qubitCount,
stepIndex,
steps: serializedSteps,
- targets: this.visibleQubitCircleKets
+ targets: this.visibleQubitCircleKets,
+ backend: backend !== '' ? backend : null
})
}