Source code for the TKET quantum compiler, Python bindings and utilities

Overview

tket

Introduction

This repository contains the full source code for tket, a quantum SDK.

If you just want to use tket via Python, the easiest way is to install it with pip:

pip install pytket

For full API documentation, as well as a comprehensive user manual and a selection of example notebooks, please follow the links from the pytket main page.

Note that the various pytket extensions (which allow pytket to interface with other software packages and with quantum devices) live in the separate pytket-extensions repository.

If you would like to build tket yourself and help to improve it, read on!

The codebase is split into two main projects:

  • tket: the core functionality of tket, optimised for execution speed and implemented in C++.
  • pytket: the Python interface of tket. This consists of binder modules to tket (written in C++ and making use of pybind11 to link to the tket shared library) and pure Python code that defines abstract interfaces used by the extension modules such as the Backend and BackendResult classes, as well as various other utilities.

How to build tket and pytket

Prerequisites

Build tools

The following compiler toolchains are used to build tket on the CI and are therefore known to work:

  • Linux: gcc-10
  • MacOS: apple-clang 13
  • Windows: MSVC 19

It is recommended that you use these versions to build locally, as code may depend on the features they support. The compiler version can be controlled by setting CC and CXX in your environment (e.g. CC=gcc-10 and CXX=g++-10), or on Debian-based Linux systems using update-alternatives.

You should also have Python (3.7, 3.8 or 3.9) and pip installed. We use cmake and the package manager conan to build tket. Both can be installed with pip:

pip install cmake conan

It is recommended that you also install ninja and ccache to speed up the build process. For example on Debian/Ubuntu:

sudo apt install ninja-build ccache

Set up conan profile

Generate a profile that matches your current machine. This profile does not have to be called tket, but if you give it another name you will have to set CONAN_TKET_PROFILE to its name in your environment when you build the Python module.

conan profile new tket --detect

If this prints a warning about gcc ABI compatibility (as it probably will on Linux), adjust the profile compiler settings with the following command, as recommended in the warning message:

conan profile update settings.compiler.libcxx=libstdc++11 tket

If you wish you can set your profile to Debug mode:

conan profile update settings.build_type=Debug tket

Test dependencies

A few of the tket tests require a working LaTeX installation, including latexmk and the quantikz package. By default these are only run on Linux. Passing ~[latex] to the test executable will disable them. To install the Latex dependencies on (Debian flavours of) Linux you can do:

sudo apt-get install texlive texlive-latex-extra latexmk
mkdir -p ~/texmf/tex/latex
wget http://mirrors.ctan.org/graphics/pgf/contrib/quantikz/tikzlibraryquantikz.code.tex -P ~/texmf/tex/latex

The Python tests require a few more packages. These can be installed with:

pip install -r pytket/tests/requirements.txt

Adding local pybind11

There is a known issue with using pybind11 from the conan-center that can lead to a Python crash when importing pytket. To remedy this, pybind11 must be installed from the local recipe:

conan remove -f pybind11/*
conan create --profile=tket recipes/pybind11

where the first line serves to remove any version already installed.

Building symengine

The symengine dependency is built from a local conan recipe. Run:

conan create --profile=tket recipes/symengine

to build it.

Building tket

Method 1

At this point you can run:

conan create --profile=tket recipes/tket

to build the tket library.

Note: by default, tket uses the header-only version of spdlog. This avoids an issue with an undefined symbol when run in some Linux virtual environments, but makes builds slower. For faster local builds you can supply the option -o tket:spdlog_ho=False to the above conan create command.

To build and run the tket tests:

conan create --profile=tket recipes/tket-tests

If you want to build them without running them, pass --test-folder None to the conan command. (You can still run them manually afterwards.)

There is also a small set of property-based tests which you can build and run with:

conan create --profile=tket recipes/tket-proptests

Now to build pytket, first install the pybind11 headers:

conan create --profile=tket recipes/pybind11

Then build the pytket module:

cd pytket
pip install -e .

And then to run the Python tests:

cd tests
pytest

Method 2

In a development cycle, it may save time to break down the conan create command from above into separate build and export commands.

First create a build folder in the project root. Then proceed as follows.

  1. To install dependencies:

    conan install recipes/tket --install-folder=build --profile=tket --build=missing
  2. To configure the build:

    conan build recipes/tket --configure --build-folder=build --source-folder=tket/src
  3. To build:

    conan build recipes/tket --build --build-folder=build
  4. To export to conan cache (necessary to build pytket):

    conan export-pkg recipes/tket -f --build-folder=build --source-folder=tket/src

Test coverage

The code coverage of the tket tests is reported here. This report is generated weekly from the develop branch.

API documentation

The tket (C++) API documentation (generated with doxygen, and still rather patchy) is available here.

The pytket (Python) API documentation is available here.

Comments
  • Separate some low-level components

    Separate some low-level components

    This is the beginning of a longer process, which will hopefully feed into TKET2, but I didn't want to go too far along before submitting a PR in case there are issues with the approach.

    The idea is to separate TKET into self-contained, versioned components that will live as conan packages on our artifactory server.

    I have started with four libraries: logging (tklog); assertions (tkassert); RNG (tkrng); and token swapping (tktokenswap).

    Don't be alarmed by the number of changed files: most are just trivial modifications to include paths. A number of source and test files have moved from the tket directory to the libs directory, but their content is unchanged except for a couple of minor fixes to avoid build warnings (since the libraries are build with slightly stricter warning flags).

    Don't be alarmed by the apparent number of new lines either: these are accounted for by the need to copy some test utility files; see below.

    The coverage test will fail in this PR. This is expected because many of the token-swapping tests have moved to the tktokenswap component -- no tests have been removed. I propose ignoring that failure (and using admin privileges to merge the PR); alternatively, I could add some more tests here and there to bring the coverage level up.

    The CI workflows for the new libraries are as follows:

    • (test_libs.yml) When a PR changes anything in one of the library directories, that library is built and tested on Linux/MacOS(x86_64+arm64)/Windows; also the test coverage for the library is determined and compared with the current coverage from develop; if the line coverage goes down the workflow fails. When it is pushed todevelop, everything is tested again and the new coverage uploaded. Coverage reports are available at (e.g. for tkrng) https://cqcl.github.io/tket/tkrng/test-coverage/ .
    • (build_libs.yml) When the conanfile in one of the libraries changes (e.g. if the version number is increased), the new library is built (in all combinations of release and debug, shared and static, for Linux/MacOS(x86_64+arm64)/Windows/manylinux); on push to develop these get uploaded to the tket conan repo. (The main tket build would need to be subsequently updated to use the new versions in place of the old.)

    The library directories all have the same structure; and to some extent this structure is assumed by the workflow scripts, so should be adhered to as new libraries are added:

    libs/<libname>/
    ├── conanfile.py
    ├── src
    │   ├── CMakeLists.txt
    │   ├── include
    │   │   └── <libname>
    │   │       └── <public headers>.hpp
    │   └── <source files>.cpp
    ├── test
    │   ├── CMakeLists.txt
    │   ├── conanfile.py
    │   └── <unit tests>.cpp
    └── test_package
        ├── CMakeLists.txt
        ├── conanfile.py
        └── example.cpp
    

    A note on the token-swapping tests: The existing unit test source files for token-swapping are divided into those that depend on Architecture in some way and those that don't. The former have been left in the main tket unit test suite, while the latter have been become tktokenswap unit tests. However, both sets of files make use of some utility methods defined in subdirectories of tket/tests/TokenSwapping/. I have simply copied those files into the libs/tktokenswap/test directory. I could have made symlinks instead, but this creates an ugly cross-dependency and I anticipate they will diverge over time.

    opened by cqc-alec 10
  • [TKET-1913] Refactor long running tests

    [TKET-1913] Refactor long running tests

    This PR is a refactoring of the current tests and CI so those tests that have a running time >= 1 second (on a regular modern laptop) are executed only once a week. It includes the following changes:

    • The long tests have the "[.long]" tag, which means that they are by default hidden, and can be run by specifying the "[long]" tag to the test_tket binary. NOTE: making a scenario hidden has the side-effect that its tags are not reported if you run the catch2 binary with -t to list the tags.
    • Remove the TKET_TESTS_FULL compilation flag so now all the tests are built at once.
    • Refactor some of the tests so only the long running GIVEN cases are assigned the "[.long]" flag.
    • Add the tket-tests:long option to run only the long tests.
    • Change the coverage.yml to generate and check 2 different coverage reports, one for the normal tests, and one for the full suite tests.
    opened by ferbetanzo 9
  • [TKET-1670] Expose free symbols

    [TKET-1670] Expose free symbols

    Fixes TKET-1670.

    This PR addresses exposing the free_symbols method from the underlying gate at the op level in Python. It also adds an pybind11 custom exception to be thrown in Python if the method is not defined for that gate.

    However, local checks return an empty set in that case.

    opened by Roland-djee 7
  • Prevent concurrent access to `gh-pages` branch by different workflows.

    Prevent concurrent access to `gh-pages` branch by different workflows.

    Fixes #63 .

    Somewhat tested:

    • https://github.com/CQCL/tket/actions/runs/1336599603 (release.yml)
    • https://github.com/CQCL/tket/actions/runs/1336599604 (docs.yml)
    • https://github.com/CQCL/tket/actions/runs/1336599605 (coverage.yml)
    opened by cqc-alec 7
  • ECR gate not properly supported in QASM export

    ECR gate not properly supported in QASM export

    The following simple code snippet

    from pytket import Circuit
    from pytket.qasm import circuit_to_qasm_str
    circuit = Circuit(2)
    circuit.ECR(0, 1)
    print(circuit_to_qasm_str(circuit))
    

    Unexpectedly (to me) raises an exception

    Traceback (most recent call last):
      File "<...>/test.py", line 7, in <module>
        print(circuit_to_qasm_str(circuit))
      File "<...>/venv/lib/python3.10/site-packages/pytket/qasm/qasm.py", line 811, in circuit_to_qasm_str
        circuit_to_qasm_io(circ, buffer, header=header)
      File "<...>/venv/lib/python3.10/site-packages/pytket/qasm/qasm.py", line 1076, in circuit_to_qasm_io
        raise QASMUnsupportedError(
    pytket.qasm.qasm.QASMUnsupportedError: Gate of type ecr is not defined in header qelib1.inc
    

    While it is, of course, true that the ecr gate is not part of the standard qelib1.inc, I would have expected tket to provide a corresponding QASM gate definition. Specifically, I would have expected the above script to produce something like

    OPENQASM 2.0;
    include "qelib1.inc";
    gate rzx(param0) q0,q1 { h q1; cx q0,q1; rz(param0) q1; cx q0,q1; h q1; }
    gate ecr q0,q1 { rzx(pi/4) q0,q1; x q0; rzx(-pi/4) q0,q1; }
    qreg q[2];
    ecr q[0],q[1];
    

    similar to how qiskit itself dumps such circuits.


    pytket version: 1.5.2 os: Ubuntu 22.04 python version: 3.10.6

    opened by burgholzer 6
  • Add new conan remote and use pre-built symengine package

    Add new conan remote and use pre-built symengine package

    The plan is to have tket components individually versioned, packaged and hosted on tket.jfrog.io in a new tket-conan repository. This should help make tket more modular and extensible, as well as reducing build times.

    As a "warm-up", and to save having to build symengine on the CI, I have:

    • added a workflow that builds symengine (from our own recipe) and uploads the packages to tket-conan, in several configurations (4 platforms x Release/Debug x shared/static);
    • changed the CI workflows that build tket so that they can just download symengine from the new remote instead of having to build it;
    • added the necessary credentials as github secrets;
    • run the workflows, to test them and populate the repository.

    The build_symengine workflow is run only for PRs and pushes to develop that change the symengine recipe. In the PR workflow the artefacts are not actually uploaded; in the push workflow they are.

    opened by cqc-alec 6
  • Use header-only version of spdlog/fmt.

    Use header-only version of spdlog/fmt.

    Closes #43 . Closes #42 .

    I am in two minds about merging this. It gets rid of the linker warnings, and fixes the problem with manylinux builds, but makes builds somewhat slower.

    opened by cqc-alec 6
  • Segmentation Fault with tket::Circuit::CommandIterator::operator++() for pytket

    Segmentation Fault with tket::Circuit::CommandIterator::operator++() for pytket

    When applying a RoutingPass to an RB circuit with more than 5 qubits with pytket, a Segmentation Fault is raised from tket::Circuit::CommandIterator::operator++(). This is consistently occuring with both Windows and Ubuntu (WSL) versions of pytket.

    The gdb output is as so:

    #0  0x00007fffa537e59f in tket::Circuit::CommandIterator::operator++() ()
       from /home/andrew/.local/lib/python3.8/site-packages/pytket/_tket/../../pytket.libs/libtket-Circuit-8a15d38f.so
    #1  0x00007fffd3c54c30 in ?? ()
       from /home/andrew/.local/lib/python3.8/site-packages/pytket/_tket/circuit.cpython-38-x86_64-linux-gnu.so
    #2  0x00007fffd3bdc317 in ?? ()
       from /home/andrew/.local/lib/python3.8/site-packages/pytket/_tket/circuit.cpython-38-x86_64-linux-gnu.so
    #3  0x00000000005f6929 in PyCFunction_Call ()
    #4  0x00000000005f74f6 in _PyObject_MakeTpCall ()
    #5  0x000000000050c333 in ?? ()
    #6  0x00000000005fe736 in ?? ()
    #7  0x00000000005abf99 in ?? ()
    #8  0x000000000056be9c in _PyEval_EvalFrameDefault ()
    #9  0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #10 0x00000000005f6eb3 in _PyFunction_Vectorcall ()
    #11 0x000000000056cc1f in _PyEval_EvalFrameDefault ()
    #12 0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #13 0x00000000005f6eb3 in _PyFunction_Vectorcall ()
    #14 0x000000000056bacd in _PyEval_EvalFrameDefault ()
    #15 0x00000000005f6cd6 in _PyFunction_Vectorcall ()
    #16 0x000000000056bacd in _PyEval_EvalFrameDefault ()
    #17 0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #18 0x00000000005f6eb3 in _PyFunction_Vectorcall ()
    #19 0x000000000056bbfa in _PyEval_EvalFrameDefault ()
    #20 0x00000000005f6cd6 in _PyFunction_Vectorcall ()
    #21 0x000000000056bbfa in _PyEval_EvalFrameDefault ()
    #22 0x00000000005f6cd6 in _PyFunction_Vectorcall ()
    #23 0x000000000056bbfa in _PyEval_EvalFrameDefault ()
    #24 0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #25 0x000000000050bca0 in ?? ()
    #26 0x000000000056cc1f in _PyEval_EvalFrameDefault ()
    #27 0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #28 0x00000000005f6eb3 in _PyFunction_Vectorcall ()
    #29 0x000000000056bbfa in _PyEval_EvalFrameDefault ()
    #30 0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #31 0x00000000005f6eb3 in _PyFunction_Vectorcall ()
    #32 0x000000000056bbfa in _PyEval_EvalFrameDefault ()
    #33 0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #34 0x00000000005f6eb3 in _PyFunction_Vectorcall ()
    #35 0x000000000056cc1f in _PyEval_EvalFrameDefault ()
    #36 0x0000000000569dba in _PyEval_EvalCodeWithName ()
    #37 0x00000000006902a7 in PyEval_EvalCode ()
    #38 0x000000000067f951 in ?? ()
    #39 0x000000000067f9cf in ?? ()
    #40 0x000000000067fa71 in ?? ()
    #41 0x0000000000681b97 in PyRun_SimpleFileExFlags ()
    #42 0x00000000006b9d32 in Py_RunMain ()
    #43 0x00000000006ba0bd in Py_BytesMain ()
    #44 0x00007ffff7df2083 in __libc_start_main (main=0x4efd60 <main>, argc=2, argv=0x7fffffffe058, init=<optimized out>,
        fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe048) at ../csu/libc-start.c:308
    #45 0x00000000005fc5fe in _start ()
    

    I don't have a specific circuit that is causing this (as Python is hard crashing when the seg fault happens), but I can consistently make it occur when there are 6 qubits and at least 80 gates.

    As the quality of the gdb output suggests, I'm not too familiar with C++ and don't really know what I should be looking for or what information is useful, but will happily try out different things if given direction

    bug 
    opened by barney54321 5
  • TK2 synthesis pass

    TK2 synthesis pass

    Add a new transform and pass to efficiently convert to the TK1/TK2 basis.

    This is "best effort" at finding efficient TK2 decompositions of standard gates. I have left TODO comments where we should be able to do better but I have not been able to figure out how: I will raise a new issue for those cases.

    opened by cqc-alec 4
  • Generic QIR generation for custom gate set.

    Generic QIR generation for custom gate set.

    This PR addresses the development of QIR generation functionality for arbitrary input gate set. This encompasses:

    • The definition of new data structures to define a gate set and conversion from pytket optypes to the input gate set.
    • The definition of a ExtendedModule class that uses the add_external_function to define new function calls in QIR for the custom defined gate set.
    • Behaviour in both cases:
      • Default: uses PyQIR gate set
      • If input gate set, uses ExtendedModule
    opened by Roland-djee 4
  • fix wire swap handling in the creation of a phase poly box [TKET-1653]

    fix wire swap handling in the creation of a phase poly box [TKET-1653]

    Fixes: [TKET-1653] No wireswap handling in the creation of a phase poly box #126

    I have decided to add this in the creation of the phase poly box to make sure it is not used in other cases. This is probably very inefficient in other cases, the efficient solution is found in the decomposition of the ppb.

    opened by cqc-melf 4
  • nb viewer link

    nb viewer link

    I created an examples.html documentation page with the links to the various examples which can be viewed through the nbviewer.

    This will allow the notebooks to be downloaded but the notebooks themselves will not be executed (this requires binder which takes ages to build for the pytket examples).

    This is a small change but seems minimally invasive for now and will not require conversion to .rst files or refactoring of our examples repository.

    There is a download option available but it seems that you have to right click on the download button and click "save as" for it to work properly. I haven't figured out why this is the case but it seems to be addressed in this issue.

    https://github.com/jupyter/nbviewer/issues/756

    opened by CalMacCQ 8
  • Coherent Tableau

    Coherent Tableau

    Took a bit longer than expected to get the synthesis algorithm working, but we now have a working draft implementation for Coherent Tableaux. This PR covers the basic data structure, manipulations, and conversions to and from circuits. The conversion to circuits will need amendment once we support post-selections in tket. The main current use case for this is in the upcoming PauliGraph refactor (useful for generalising PauliSimp and ZX/MBQC extraction), but could also be provided with a Python interface and boxes like we have for UnitaryTableau.

    opened by willsimmons1465 0
  • Qiskit embedding example in manual is subject to depreciation

    Qiskit embedding example in manual is subject to depreciation

    https://cqcl.github.io/pytket/manual/manual_backend.html#embedding-into-qiskit

    this line: grover = Grover(quantum_instance=qinstance)

    the quantum_instance will be deprecated in a future qiskit release

    opened by yao-cqc 0
  • Add metadata to ops

    Add metadata to ops

    This PR addresses the addition of a metadata member to various classes for the purposes of tag propagation.

    Specifically:

    • Op type and MetaOp, Gate and ClassicalOp subtypes.

    • Box (as an Op subtype) and CircuitBox and ClassicalExpBox subtypes.

    • [ ] Python binders.

    opened by Roland-djee 0
Releases(v1.9.0rc0)
Owner
Cambridge Quantum
Quantum Software and Technologies
Cambridge Quantum
A C++ framework for MDPs and POMDPs with Python bindings

AI-Toolbox This C++ toolbox is aimed at representing and solving common AI problems, implementing an easy-to-use interface which should be hopefully e

Eugenio Bargiacchi 577 Nov 22, 2022
PyCppAD — Python bindings for CppAD Automatic Differentiation library

PyCppAD is an open source framework which provides bindings for the CppAD Automatic Differentiation(CppAD) C++ library in Python. PyCppAD also includes support for the CppADCodeGen (CppADCodeGen), C++ library, which exploits CppAD functionality to perform code generation.

SimpleRobotics 14 Nov 14, 2022
An open-source, low-code machine learning library in Python

An open-source, low-code machine learning library in Python ?? Version 2.3.6 out now! Check out the release notes here. Official • Docs • Install • Tu

PyCaret 6.6k Nov 28, 2022
Mirror of compiler project code. Not for SVC purpose.

Compiler-proj Project progress is updated here. Progress 2021/11/28: Started! Set up Makefile and finished basic scanner. 2021/10/24: Repo created. Ac

Yuheng 0 Dec 23, 2021
Golang bindings for Nvidia Datacenter GPU Manager (DCGM)

Bindings Golang bindings are provided for NVIDIA Data Center GPU Manager (DCGM). DCGM is a set of tools for managing and monitoring NVIDIA GPUs in clu

NVIDIA Corporation 37 Nov 8, 2022
An open source python library for automated feature engineering

"One of the holy grails of machine learning is to automate more and more of the feature engineering process." ― Pedro Domingos, A Few Useful Things to

alteryx 6.4k Nov 23, 2022
Triton - a language and compiler for writing highly efficient custom Deep-Learning primitives.

Triton - a language and compiler for writing highly efficient custom Deep-Learning primitives.

OpenAI 4.3k Nov 25, 2022
BladeDISC - BladeDISC is an end-to-end DynamIc Shape Compiler project for machine learning workloads.

BladeDISC Introduction Overview Features and Roadmap Frontend Framework Support Matrix Backend Support Matrix Deployment Solutions Numbers of Typical

Alibaba 488 Nov 19, 2022
Scalable, Portable and Distributed Gradient Boosting (GBDT, GBRT or GBM) Library, for Python, R, Java, Scala, C++ and more. Runs on single machine, Hadoop, Spark, Dask, Flink and DataFlow

eXtreme Gradient Boosting Community | Documentation | Resources | Contributors | Release Notes XGBoost is an optimized distributed gradient boosting l

Distributed (Deep) Machine Learning Community 23.5k Nov 22, 2022
High performance, easy-to-use, and scalable machine learning (ML) package, including linear model (LR), factorization machines (FM), and field-aware factorization machines (FFM) for Python and CLI interface.

What is xLearn? xLearn is a high performance, easy-to-use, and scalable machine learning package that contains linear model (LR), factorization machin

Chao Ma 3k Nov 25, 2022
A fast, scalable, high performance Gradient Boosting on Decision Trees library, used for ranking, classification, regression and other machine learning tasks for Python, R, Java, C++. Supports computation on CPU and GPU.

Website | Documentation | Tutorials | Installation | Release Notes CatBoost is a machine learning method based on gradient boosting over decision tree

CatBoost 6.8k Nov 26, 2022
In-situ data analyses and machine learning with OpenFOAM and Python

PythonFOAM: In-situ data analyses with OpenFOAM and Python Using Python modules for in-situ data analytics with OpenFOAM 8. NOTE that this is NOT PyFO

Argonne Leadership Computing Facility - ALCF 113 Nov 12, 2022
Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more

Apache MXNet (incubating) for Deep Learning Apache MXNet is a deep learning framework designed for both efficiency and flexibility. It allows you to m

The Apache Software Foundation 20.2k Nov 18, 2022
Tensors and Dynamic neural networks in Python with strong GPU acceleration

PyTorch is a Python package that provides two high-level features: Tensor computation (like NumPy) with strong GPU acceleration Deep neural networks b

null 60.5k Nov 23, 2022
Implement yolov5 with Tensorrt C++ api, and integrate batchedNMSPlugin. A Python wrapper is also provided.

yolov5 Original codes from tensorrtx. I modified the yololayer and integrated batchedNMSPlugin. A yolov5s.wts is provided for fast demo. How to genera

weiwei zhou 45 Oct 21, 2022
Upload and changes to Python 0.9.1 release (from 1991!) so that it would compile

This is Python, an extensible interpreted programming language that combines remarkable power with very clear syntax. This is version 0.9 (the first

Skip Montanaro 137 Nov 13, 2022
ParaMonte: Plain Powerful Parallel Monte Carlo and MCMC Library for Python, MATLAB, Fortran, C++, C.

Overview | Installation | Dependencies | Parallelism | Examples | Acknowledgments | License | Authors ParaMonte: Plain Powerful Parallel Monte Carlo L

Computational Data Science Lab 178 Nov 21, 2022