Skip to content

Commit

Permalink
Merge pull request #37 from Cornell-QCA/init-braiding
Browse files Browse the repository at this point in the history
  • Loading branch information
Haadi-Khan authored Jun 16, 2024
2 parents 8dae22f + 2a60362 commit 974374a
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 64 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/workflows/Maturin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# This file is autogenerated by maturin v1.6.0
# To update, run
#
# maturin generate-ci github
#
name: CI

on:
push:
branches:
- main
- master
tags:
- '*'
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
linux:
runs-on: ${{ matrix.platform.runner }}
strategy:
matrix:
platform:
- runner: ubuntu-latest
target: x86_64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-linux-${{ matrix.platform.target }}
path: dist

release:
name: Release
runs-on: ubuntu-latest
if: "startsWith(github.ref, 'refs/tags/')"
needs: [linux]
steps:
- uses: actions/download-artifact@v4
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --non-interactive --skip-existing wheels-*/*
File renamed without changes.
16 changes: 0 additions & 16 deletions .ruff.toml

This file was deleted.

31 changes: 31 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,39 @@ classifiers = [
]
dynamic = ["version"]

[tool.pytest.ini_options]
markers = [
"main",
"fusion",
"braiding",
"state",
"model",
"anyon",
"basis"
]

[tool.maturin]
features = ["pyo3/extension-module"]

[tool.ruff]
lint.select = ["E", "F"]
lint.ignore = ["F405", "F403"]
exclude = [
"build",
"dist",
"venv",
".venv"
]
line-length = 120

[tool.ruff.lint.per-file-ignores]
"tools/ignore.py" = ["F401"]
"python/anyon_braiding_simulator/__init__.py" = ["ALL"]

[tool.ruff.format]
quote-style = "single"
indent-style = "space"
docstring-code-format = true

[tool.pyright]
include = ["python", "target/wheels", "venv/lib/python3.12/site-packages/"]
13 changes: 12 additions & 1 deletion python/anyon_braiding_simulator/Braiding.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import numpy as np
from anyon_braiding_simulator import Anyon
from Model import Model


def apply_unitary(state, unitary):
Expand Down Expand Up @@ -46,7 +47,7 @@ def track_state_history(model, initial_state, operations):


class Braid:
def __init__(self, anyons: list[Anyon]):
def __init__(self, anyons: list[Anyon], model: Model):
"""
Parameters:
anyons (list): List of Anyon objects
Expand All @@ -61,6 +62,16 @@ def __init__(self, anyons: list[Anyon]):
if len(names) != len(set(names)):
raise ValueError('Duplicate anyon names detected')

# Check if all charges of given anyons are included in given model
charges = model.get_charges()
invalid_anyons = [anyon for anyon in anyons if anyon.topo_charge not in charges]
if invalid_anyons:
names_and_charges = [f'Name: {anyon.name}, Charge: {anyon.topo_charge}' for anyon in invalid_anyons]
message = "The following anyons have charges that aren't defined in the given model:\n" + '\n'.join(
names_and_charges
)
raise ValueError(message)

self.anyons = anyons
self.operations = []
self.initial_states = []
Expand Down
6 changes: 6 additions & 0 deletions python/anyon_braiding_simulator/Model.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ def __init__(self, model_type: AnyonModel, num_fusion_channels=5) -> None:

self._num_fusion_channels = num_fusion_channels

def get_charges(self) -> set:
"""
Provide the charges that are defined in this model.
"""
return self._charges

def getFMatrix(self, a: str, b: str, c: str, d: str) -> np.ndarray:
"""
Parameters
Expand Down
17 changes: 15 additions & 2 deletions python/anyon_braiding_simulator/Simulator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from anyon_braiding_simulator import Anyon, Model
from Model import Model


class Simulator:
Expand All @@ -9,8 +9,9 @@ def __init__(self):
"""
self._anyons = []
self._model = None
self._dim_of_anyon_pos = 2 # Default is 2D anyon positions

def update_anyons(self, is_increasing: bool, anyons: list(Anyon)) -> None:
def update_anyons(self, is_increasing: bool, anyons: list) -> None:
"""
Update the anyons stored in memory.
Expand All @@ -35,6 +36,18 @@ def list_anyons(self) -> list:
"""
return self._anyons

def get_dim_of_anyon_pos(self) -> int:
"""
Provides the dimension of anyon positions.
"""
return self._dim_of_anyon_pos

def switch_to_1D(self) -> None:
"""
Sets the dimension of anyon positions to be 1.
"""
self._dim_of_anyon_pos = 1

def contains_anyon(self, anyon_name: str) -> bool:
"""
Check if the anyon is in the simulator.
Expand Down
109 changes: 93 additions & 16 deletions python/anyon_braiding_simulator/main.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Standard Library
import cmd
import subprocess
import sys

from anyon_braiding_simulator import Anyon, AnyonModel, IsingTopoCharge, Model
from anyon_braiding_simulator import Anyon, AnyonModel, IsingTopoCharge
from Braiding import Braid
from Model import Model
from Simulator import Simulator

sim = Simulator()
Expand All @@ -13,11 +15,12 @@ def anyon(*args):
"""
Handle the anyon command. This command adds an anyon to the simulation.
"""
if len(args) < 3:
print('Error: Not enough arguments')
if len(args) != 2 and len(args) != 3:
print('Error: There should be either 2 or 3 arguments')
return

name = args[0]
topological_charge = args[1]

try:
topo_charge = {
Expand All @@ -30,21 +33,45 @@ def anyon(*args):
print('Error: topological charge must be a number')
return

try:
position = tuple(map(float, args[2].replace('{', '').replace('}', '').split(',')))
position[1]
except ValueError:
print('Error: position must be formatted as {x, y} where x and y are numbers')
return
except IndexError:
print('Error: position must be formatted as {x, y} where x and y are numbers')
return
if len(args) == 2:
anyons = sim.list_anyons()
# Make sure any previous anyons were specified in 1D space (i.e. without a position argument)
if anyons and sim.get_dim_of_anyon_pos() == 2:
print(
'Error: you have already provided an anyon in 2D space, so the rest must also have a \
specified 2D position'
)
return
elif not anyons:
sim.switch_to_1D()

position_1D = len(anyons) # Index/position of new anyon in 1D
position = (position_1D, 0)
print(f'Created anyon {name} with TC {topological_charge} at position {position_1D} in 1D')
else:
# Make sure any previous anyons were specified in 2D space
if sim.get_dim_of_anyon_pos() == 1:
print(
'Error: you have already provided an anyon in 1D space, so the positions of the rest \
cannot be specified in 2D'
)
return

try:
position = tuple(map(float, args[2].replace('{', '').replace('}', '').split(',')))
position[1]
except ValueError:
print('Error: position must be formatted as {x,y} where x and y are numbers')
return
except IndexError:
print('Error: position must be formatted as {x,y} where x and y are numbers')
return

print(f'Created anyon {name} with TC {topological_charge} at position {position} in 2D')

new_anyon = Anyon(name, topological_charge, position)
sim.update_anyons(True, [new_anyon])

print(f'Created anyon {name} with TC {topological_charge} at position {position}')


def model(*args):
"""
Expand Down Expand Up @@ -99,7 +126,7 @@ def braid(*args):
print('Error: Not enough arguments')
return

braid = Braid(sim.list_anyons())
braid = Braid(sim.list_anyons(), sim._model)
cmd = args[0]

if cmd.lower() == 'swap':
Expand All @@ -125,6 +152,48 @@ def __init__(self):
'list': 'list',
}

# Flag to indicate whether initialization (model & anyon choice) is completed
self.init_completed = False

# Prompt the user to input the anyon model
while True:
user_input = input('Enter the anyon model ("ising" or "fibonacci"): ')
if user_input.lower() == 'ising' or user_input.lower() == 'fibonacci':
break
elif user_input.lower() == 'exit':
sys.exit(0)
else:
print('\nError: Invalid model.')
input_to_model_type = {'ising': AnyonModel.Ising, 'fibonacci': AnyonModel.Fibonacci}
model(input_to_model_type[user_input.lower()])

# Prompt the user to input the anyon details
no_anyons = True
while True:
if no_anyons:
user_input = input(
'\nEnter the anyon name, topological charge, and optionally, the 2D position.'
'\nUse the format <name> <topological charge> <{x,y}>.\n'
'> '
)
else:
user_input = input('\nContinue adding anyons, or type "done" when finished initializing.\n' '> ')

if user_input.lower() == 'exit':
sys.exit(0)
elif user_input.lower() == 'done':
break

args = user_input.split(' ')
if len(args) < 2 or len(args) > 3:
print('Error: There should be either 2 or 3 arguments')
continue

anyon(*args)
no_anyons = False

self.init_complete = True

def do_shell(self, arg):
"Run a shell command"
print('running shell command:', arg)
Expand All @@ -135,6 +204,10 @@ def do_shell(self, arg):

def do_anyon(self, arg):
"Add an anyon to the simulation"
if self.init_complete:
print('Error: Cannot add anyons after initialization')
return

args = arg.split(' ')
if args[0] == 'help' or args[0] == '-h':
print(self.command_options['anyon'])
Expand All @@ -143,6 +216,10 @@ def do_anyon(self, arg):

def do_model(self, arg):
"Set the model for the simulation"
if self.init_complete:
print('Error: Cannot change model after initialization')
return

args = arg.split(' ')
model(*args)
if args[0] == 'help' or args[0] == '-h':
Expand Down Expand Up @@ -181,7 +258,7 @@ def do_exit(self, arg):

def do_help(self, arg):
"Print help"
print('Commands: anyon, model, fusion, braid, exit, help')
print('Commands: fusion, braid, exit, help')


if __name__ == '__main__':
Expand Down
2 changes: 2 additions & 0 deletions python/tests/test_anyon.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pytest
from anyon_braiding_simulator import Anyon, IsingTopoCharge


@pytest.mark.anyon
def test_anyon():
anyon = Anyon('thisisatest', IsingTopoCharge.Psi, (1, 1))
assert anyon.name == 'thisisatest'
Expand Down
Loading

0 comments on commit 974374a

Please sign in to comment.