From fdf6f41a89fa76e2386cbb18ada7ca9fee77ef80 Mon Sep 17 00:00:00 2001 From: aquint-zama Date: Mon, 13 Mar 2023 09:17:59 +0100 Subject: [PATCH] docs(frontend/python): overhaul python frontend docs --- .github/ISSUE_TEMPLATE/new_operator.md | 2 +- .github/workflows/block_merge.yml | 2 +- README.md | 165 +++++++++- UPGRADING.md | 65 ++++ docs/README.md | 36 +++ .../concrete-python/docs => docs}/SUMMARY.md | 5 +- .../compiling_and_executing_example_graph.png | Bin .../compilation-pipeline/two_x_plus_three.png | Bin .../_static/float_fusing_example/after.png | Bin .../after_bigger_search.png | Bin .../_static/float_fusing_example/before.png | Bin .../before_bigger_search.png | Bin .../_static/float_fusing_example/subgraph.png | Bin .../subgraph_bigger_search.png | Bin .../_static/mlir/MLIR_conversion.png | Bin .../_static/p_error_simulation.pdf | Bin .../_static/rounded-tlu/10-bits-removed.png | Bin .../_static/rounded-tlu/12-bits-removed.png | Bin .../_static/rounded-tlu/4-bits-kept.png | Bin .../_static/rounded-tlu/6-bits-kept.png | Bin .../_static/rounded-tlu/relu.png | Bin .../artifacts/manual/1.initial.graph.png | Bin .../artifacts/manual/2.after-fusing.graph.png | Bin .../artifacts/manual/3.final.graph.png | Bin .../table-lookup/1.initial.graph.png | Bin .../tutorials/table-lookup/3.final.graph.png | Bin .../docs => docs}/_static/zama_home_docs.png | Bin 386309 -> 385203 bytes docs/conftest.py | 1 + .../docs => docs}/dev/compilation.md | 22 +- docs/dev/contributing.md | 6 + docs/dev/fusing.md | 33 ++ .../docs => docs}/dev/releasing.md | 2 +- docs/dev/terminology_and_structure.md | 24 ++ .../getting-started/compatibility.md | 0 .../getting-started/exactness.md | 8 +- docs/getting-started/installing.md | 21 ++ docs/getting-started/performance.md | 35 ++ .../getting-started/quick_start.md | 10 +- .../docs => docs}/howto/configure.md | 33 +- docs/howto/debug.md | 305 ++++++++++++++++++ .../docs => docs}/howto/deploy.md | 16 +- .../docs => docs}/tutorial/decorator.md | 4 +- .../docs => docs}/tutorial/direct_circuits.md | 22 +- docs/tutorial/extensions.md | 205 ++++++++++++ .../docs => docs}/tutorial/floating_points.md | 16 +- .../docs => docs}/tutorial/formatting.md | 2 +- .../tutorial/key_value_database.ipynb | 0 .../tutorial/key_value_database.md | 0 .../tutorial/rounded_table_lookups.md | 26 +- .../docs => docs}/tutorial/simulation.md | 4 +- .../docs => docs}/tutorial/table_lookups.md | 46 ++- .../docs => docs}/tutorial/tagging.md | 8 +- frontends/concrete-python/README.md | 158 +-------- .../concrete/fhe/compilation/utils.py | 8 +- frontends/concrete-python/docs/README.md | 24 -- .../artifacts/auto/1.initial.graph.png | Bin 8607 -> 0 bytes .../artifacts/auto/2.final.graph.png | Bin 8607 -> 0 bytes frontends/concrete-python/docs/conftest.py | 1 - .../concrete-python/docs/dev/contributing.md | 99 ------ frontends/concrete-python/docs/dev/docker.md | 45 --- frontends/concrete-python/docs/dev/fusing.md | 37 --- frontends/concrete-python/docs/dev/mlir.md | 17 - .../concrete-python/docs/dev/project_setup.md | 91 ------ .../docs/dev/terminology_and_structure.md | 26 -- .../docs/getting-started/installing.md | 46 --- .../docs/getting-started/performance.md | 104 ------ frontends/concrete-python/docs/howto/debug.md | 265 --------------- .../docs/linux.dependency.licenses.txt | 21 -- .../docs/tutorial/extensions.md | 153 --------- 69 files changed, 1000 insertions(+), 1219 deletions(-) create mode 100644 UPGRADING.md create mode 100644 docs/README.md rename {frontends/concrete-python/docs => docs}/SUMMARY.md (88%) rename {frontends/concrete-python/docs => docs}/_static/basics/compiling_and_executing_example_graph.png (100%) rename {frontends/concrete-python/docs => docs}/_static/compilation-pipeline/two_x_plus_three.png (100%) rename {frontends/concrete-python/docs => docs}/_static/float_fusing_example/after.png (100%) rename {frontends/concrete-python/docs => docs}/_static/float_fusing_example/after_bigger_search.png (100%) rename {frontends/concrete-python/docs => docs}/_static/float_fusing_example/before.png (100%) rename {frontends/concrete-python/docs => docs}/_static/float_fusing_example/before_bigger_search.png (100%) rename {frontends/concrete-python/docs => docs}/_static/float_fusing_example/subgraph.png (100%) rename {frontends/concrete-python/docs => docs}/_static/float_fusing_example/subgraph_bigger_search.png (100%) rename {frontends/concrete-python/docs => docs}/_static/mlir/MLIR_conversion.png (100%) rename {frontends/concrete-python/docs => docs}/_static/p_error_simulation.pdf (100%) rename {frontends/concrete-python/docs => docs}/_static/rounded-tlu/10-bits-removed.png (100%) rename {frontends/concrete-python/docs => docs}/_static/rounded-tlu/12-bits-removed.png (100%) rename {frontends/concrete-python/docs => docs}/_static/rounded-tlu/4-bits-kept.png (100%) rename {frontends/concrete-python/docs => docs}/_static/rounded-tlu/6-bits-kept.png (100%) rename {frontends/concrete-python/docs => docs}/_static/rounded-tlu/relu.png (100%) rename {frontends/concrete-python/docs => docs}/_static/tutorials/artifacts/manual/1.initial.graph.png (100%) rename {frontends/concrete-python/docs => docs}/_static/tutorials/artifacts/manual/2.after-fusing.graph.png (100%) rename {frontends/concrete-python/docs => docs}/_static/tutorials/artifacts/manual/3.final.graph.png (100%) rename {frontends/concrete-python/docs => docs}/_static/tutorials/table-lookup/1.initial.graph.png (100%) rename {frontends/concrete-python/docs => docs}/_static/tutorials/table-lookup/3.final.graph.png (100%) rename {frontends/concrete-python/docs => docs}/_static/zama_home_docs.png (70%) create mode 120000 docs/conftest.py rename {frontends/concrete-python/docs => docs}/dev/compilation.md (82%) create mode 100644 docs/dev/contributing.md create mode 100644 docs/dev/fusing.md rename {frontends/concrete-python/docs => docs}/dev/releasing.md (91%) create mode 100644 docs/dev/terminology_and_structure.md rename {frontends/concrete-python/docs => docs}/getting-started/compatibility.md (100%) rename {frontends/concrete-python/docs => docs}/getting-started/exactness.md (72%) create mode 100644 docs/getting-started/installing.md create mode 100644 docs/getting-started/performance.md rename {frontends/concrete-python/docs => docs}/getting-started/quick_start.md (87%) rename {frontends/concrete-python/docs => docs}/howto/configure.md (74%) create mode 100644 docs/howto/debug.md rename {frontends/concrete-python/docs => docs}/howto/deploy.md (91%) rename {frontends/concrete-python/docs => docs}/tutorial/decorator.md (88%) rename {frontends/concrete-python/docs => docs}/tutorial/direct_circuits.md (82%) create mode 100644 docs/tutorial/extensions.md rename {frontends/concrete-python/docs => docs}/tutorial/floating_points.md (83%) rename {frontends/concrete-python/docs => docs}/tutorial/formatting.md (67%) rename {frontends/concrete-python/docs => docs}/tutorial/key_value_database.ipynb (100%) rename {frontends/concrete-python/docs => docs}/tutorial/key_value_database.md (100%) rename {frontends/concrete-python/docs => docs}/tutorial/rounded_table_lookups.md (88%) rename {frontends/concrete-python/docs => docs}/tutorial/simulation.md (96%) rename {frontends/concrete-python/docs => docs}/tutorial/table_lookups.md (76%) rename {frontends/concrete-python/docs => docs}/tutorial/tagging.md (95%) delete mode 100644 frontends/concrete-python/docs/README.md delete mode 100644 frontends/concrete-python/docs/_static/tutorials/artifacts/auto/1.initial.graph.png delete mode 100644 frontends/concrete-python/docs/_static/tutorials/artifacts/auto/2.final.graph.png delete mode 120000 frontends/concrete-python/docs/conftest.py delete mode 100644 frontends/concrete-python/docs/dev/contributing.md delete mode 100644 frontends/concrete-python/docs/dev/docker.md delete mode 100644 frontends/concrete-python/docs/dev/fusing.md delete mode 100644 frontends/concrete-python/docs/dev/mlir.md delete mode 100644 frontends/concrete-python/docs/dev/project_setup.md delete mode 100644 frontends/concrete-python/docs/dev/terminology_and_structure.md delete mode 100644 frontends/concrete-python/docs/getting-started/installing.md delete mode 100644 frontends/concrete-python/docs/getting-started/performance.md delete mode 100644 frontends/concrete-python/docs/howto/debug.md delete mode 100644 frontends/concrete-python/docs/linux.dependency.licenses.txt delete mode 100644 frontends/concrete-python/docs/tutorial/extensions.md diff --git a/.github/ISSUE_TEMPLATE/new_operator.md b/.github/ISSUE_TEMPLATE/new_operator.md index d72c6aab2..c9a0468a1 100644 --- a/.github/ISSUE_TEMPLATE/new_operator.md +++ b/.github/ISSUE_TEMPLATE/new_operator.md @@ -2,7 +2,7 @@ name: New Operator about: Organise the support of a new operator or notion in the framework. labels: feature -title: Support of **please-fill** in Concrete Numpy +title: Support of **please-fill** in Concrete --- ## Umbrella diff --git a/.github/workflows/block_merge.yml b/.github/workflows/block_merge.yml index 9fa36e666..e32fcf34a 100644 --- a/.github/workflows/block_merge.yml +++ b/.github/workflows/block_merge.yml @@ -12,7 +12,7 @@ jobs: - name: Check first line uses: gsactions/commit-message-checker@v1 with: - pattern: '^(feat|fix|test|bench|doc|chore|refactor|perf)\((compiler|backend|frontend|optimizer|tools|ci).*\): ' + pattern: '^(feat|fix|test|bench|docs|chore|refactor|perf)\((compiler|backend|frontend|optimizer|tools|ci|common).*\): ' flags: 'gs' error: 'Your first line has to contain a commit type and scope like "feat(my_feature): msg".' excludeDescription: 'true' # optional: this excludes the description body of a pull request diff --git a/README.md b/README.md index c906f5160..ec9db938f 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,158 @@ -# Concrete +

+ + +

-The `concrete` project is a set of crates that implements Zama's variant of -[TFHE](https://eprint.iacr.org/2018/421.pdf) and make it easy to use. In a nutshell, -[fully homomorphic encryption (FHE)](https://en.wikipedia.org/wiki/Homomorphic_encryption), allows -you to perform computations over encrypted data, allowing you to implement Zero Trust services. +

+ + + + + + + + + + + + + + + + + + + + +

-Concrete is based on the -[Learning With Errors (LWE)](https://cims.nyu.edu/~regev/papers/lwesurvey.pdf) and the -[Ring Learning With Errors (RLWE)](https://eprint.iacr.org/2012/230.pdf) problems, which are well -studied cryptographic hardness assumptions believed to be secure even against quantum computers. + +**Concrete** is an open-source framework which simplifies the use of fully homomorphic encryption (FHE). + +FHE is a powerful cryptographic tool, which allows computation to be performed directly on encrypted data without needing to decrypt it first. With FHE, you can build services that preserve privacy for all users. FHE is also great against data breaches as everything is done on encrypted data. Even if the server is compromised, in the end no sensitive data is leaked. + +Since writing FHE program is hard, concrete framework contains a TFHE Compiler based on LLVM to make this process easier for developers. + +## Main features + +- Ability to compile Python functions (that may use NumPy within) to their FHE equivalents, to operate on encrypted data +- Support for [large collection of operators](https://docs.zama.ai/concrete-numpy/getting-started/compatibility) +- Partial support for floating points +- Support for table lookups on integers +- Support for integration with Client / Server architectures + +## Installation + +| OS / HW | Available on Docker | Available on PyPI | +| :----------------------------------: | :-----------------: | :--------------: | +| Linux | Yes | Yes | +| Windows | Yes | No | +| Windows Subsystem for Linux | Yes | Yes | +| macOS (Intel) | Yes | Yes | +| macOS (Apple Silicon) | Yes | Yes | + + +The preferred way to install Concrete is through PyPI: + +```shell +pip install concrete-python +``` + +You can get the concrete-python docker image by pulling the latest docker image: + +```shell +docker pull zamafhe/concrete-python:v1.0.0 +``` + +You can find more detailed installation instructions in [installing.md](docs/getting-started/installing.md) + +## Getting started + +```python +from concrete import fhe + +def add(x, y): + return x + y + +compiler = fhe.Compiler(add, {"x": "encrypted", "y": "encrypted"}) +inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, 5), (5, 4)] + +print(f"Compiling...") +circuit = compiler.compile(inputset) + +print(f"Generating keys...") +circuit.keygen() + +examples = [(3, 4), (1, 2), (7, 7), (0, 0)] +for example in examples: + encrypted_example = circuit.encrypt(*example) + encrypted_result = circuit.run(encrypted_example) + result = circuit.decrypt(encrypted_result) + print(f"Evaluation of {' + '.join(map(str, example))} homomorphically = {result}") +``` + +or if you have a simple function that you can decorate, and you don't care about explicit steps of key generation, encryption, evaluation and decryption: + +```python +from concrete import fhe + +@fhe.circuit({"x": "encrypted", "y": "encrypted"}) +def add(x, y): + return x + y + +inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, 5), (5, 4)] + +print(f"Compiling...") +circuit = add.compile(inputset) + +examples = [(3, 4), (1, 2), (7, 7), (0, 0)] +for example in examples: + result = circuit.encrypt_run_decrypt(*example) + print(f"Evaluation of {' + '.join(map(str, example))} homomorphically = {result}") +``` + +## Documentation + +Full, comprehensive documentation is available at [https://docs.zama.ai/concrete](https://docs.zama.ai/concrete). + +## Target users + +Concrete is a generic library that supports a variety of use cases. Because of this flexibility, +it doesn't provide primitives for specific use cases. + +If you have a specific use case, or a specific field of computation, you may want to build abstractions on top of Concrete. + +One such example is [Concrete ML](https://github.com/zama-ai/concrete-ml), which is built on top of Concrete to simplify Machine Learning oriented use cases. + +## Tutorials + +Various tutorials are proposed in the documentation to help you start writing homomorphic programs: + +- How to use Concrete with [Decorators](https://docs.zama.ai/concrete/tutorials/decorator) +- Partial support of [Floating Points](https://docs.zama.ai/concrete/tutorials/floating_points) +- How to perform [Table Lookup](https://docs.zama.ai/concrete/tutorials/table_lookup) + +More generally, if you have built awesome projects using Concrete, feel free to let us know and we'll link to it! ## Project layout -The `concrete` project is a set of several modules which are high-level frontends, compilers, backends and side tools. - -- The `frontends` directory contains a `python` frontend. -- The `compilers` directory contains the `concrete-compiler` and `concrete-optimizer` modules. The `concrete-compiler` is a compiler that synthetize a FHE computation dag expressed as a [MLIR](https://mlir.llvm.org/) dialect, compile to a set of artifacts, and provide tools to manipulate those artifacts at runtime. The `concrete-optimizer` is a specific module used by the compiler to find the best, secure and accurate set of crypto parameters for a given dag. -- The `backends` directory contains implementations of cryptographic primitives on different computation unit, used by the `concrete-compiler` runtime. The `concrete-cpu` module provides CPU implementation, while `concrete-cuda` module provides GPU implementation using the CUDA platform. +`concrete` project is a set of several modules which are high-level frontends, compilers, backends and side tools. +- `frontends` directory contains a `python` frontend. +- `compilers` directory contains the `concrete-compiler` and `concrete-optimizer` modules. `concrete-compiler` is a compiler that: + - synthetize a FHE computation dag expressed as a [MLIR](https://mlir.llvm.org/) dialect + - compile to a set of artifacts + - and provide tools to manipulate those artifacts at runtime. +`concrete-optimizer` is a specific module used by the compiler to find the best, secure and accurate set of cryptographic parameters for a given dag. +- The `backends` directory contains implementations of cryptographic primitives on different computation unit, used by `concrete-compiler` runtime. `concrete-cpu` module provides CPU implementation, while `concrete-cuda` module provides GPU implementation using the CUDA platform. - The `tools` directory contains side tools used by the rest of the project. + +## Need support? + + + + + +## License + +This software is distributed under the BSD-3-Clause-Clear license. If you have any questions, please contact us at hello@zama.ai. diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 000000000..03c556fe1 --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,65 @@ +# Upgrading Guide + +## From `Concrete Numpy v0.x` To `Concrete v1` + +### The PyPI package `concrete-numpy` is now called `concrete-python`. + +### The module `concrete.numpy` is now called `concrete.fhe` and we advise you to use: + +```python +from concrete import fhe +``` + +instead of the previous: + +```python +import concrete.numpy as cnp +``` + +### The module `concrete.onnx` is merged into `concrete.fhe` so we advise you to use: + +```python +from concrete import fhe + +fhe.conv(...) +fhe.maxpool(...) +``` + +instead of the previous: + +```python +from concrete.onnx import connx + +connx.conv(...) +connx.maxpool(...) +``` + +### Virtual configuration option is removed. Simulation is still supported using the new `simulate` method on circuits: + +```python +from concrete import fhe + +@fhe.compiler({"x": "encrypted"}) +def f(x): + return x + 42 + +inputset = range(10) +circuit = f.compile(inputset) + +assert circuit.simulate(1) == 43 +``` + +instead of the previous: + +```python +import concrete.numpy as cnp + +@cnp.compiler({"x": "encrypted"}) +def f(x): + return x + 42 + +inputset = range(10) +circuit = f.compile(inputset, enable_unsafe_features=True, virtual=True) + +assert circuit.encrypt_run_decrypt(1) == 43 +``` diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..95d3cbdc0 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,36 @@ +# What is Concrete? + +[⭐️ Star the repo on Github](https://github.com/zama-ai/concrete) | 🗣 [Community support forum](https://community.zama.ai/c/concrete) | 📁 [Contribute to the project](dev/contributing.md) + +
+ +**Concrete** is an open-source framework which simplifies the use of fully homomorphic encryption (FHE). + +FHE is a powerful cryptographic tool, which allows computation to be performed directly on encrypted data without needing to decrypt it first. With FHE, you can build services that preserve privacy for all users. FHE is also great against data breaches as everything is done on encrypted data. Even if the server is compromised, in the end no sensitive data is leaked. + +Since writing FHE program is hard, concrete framework contains a TFHE Compiler based on LLVM to make this process easier for developers. + +## Organization of this documentation + +This documentation is split into several sections: + +* **Getting Started** gives you the basics, +* **Tutorials** gives you some essential examples on various features of the library, +* **How to** helps you perform specific tasks, +* **Developer** explains the inner workings of the library and everything related to contributing to the project. + +## Looking for support? Ask our team! + +* Support forum: [https://community.zama.ai](https://community.zama.ai) (we answer in less than 24 hours). +* Live discussion on the FHE.org discord server: [https://discord.fhe.org](https://discord.fhe.org) (inside the #**concrete** channel). +* Do you have a question about Zama? You can write us on [Twitter](https://twitter.com/zama\_fhe) or send us an email at: **hello@zama.ai** + +## How is it different from Concrete Numpy? + +Concrete Numpy was the former name of Concrete Compiler Python's frontend. Starting from v1, Concrete Compiler is now open sourced and the package name is updated from `concrete-numpy` to `concrete-python` (as `concrete` is already booked for a non FHE-related project). + +Users from Concrete-Numpy could safely update to Concrete with few changes explained in the [upgrading document](https://github.com/zama-ai/concrete/blob/main/UPGRADING.md). + +## How is it different from the previous Concrete (v0.x)? + +Before v1.0, Concrete was a set of Rust libraries implementing Zama's variant of TFHE. Starting with v1, Concrete is now Zama's TFHE compiler framework only. Rust library could be found under [TFHE-rs](https://github.com/zama-ai/tfhe-rs) project. diff --git a/frontends/concrete-python/docs/SUMMARY.md b/docs/SUMMARY.md similarity index 88% rename from frontends/concrete-python/docs/SUMMARY.md rename to docs/SUMMARY.md index 4b6fe006b..7aeffc490 100644 --- a/frontends/concrete-python/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,6 +1,6 @@ # Table of contents -* [What is Concrete Numpy?](README.md) +* [What is Concrete?](README.md) ## Getting Started @@ -31,10 +31,7 @@ ## Developer -* [Project Setup](dev/project\_setup.md) -* [Docker Setup](dev/docker.md) * [Contribute](dev/contributing.md) * [Terminology and Structure](dev/terminology\_and\_structure.md) * [Compilation](dev/compilation.md) * [Fusing](dev/fusing.md) -* [MLIR](dev/mlir.md) diff --git a/frontends/concrete-python/docs/_static/basics/compiling_and_executing_example_graph.png b/docs/_static/basics/compiling_and_executing_example_graph.png similarity index 100% rename from frontends/concrete-python/docs/_static/basics/compiling_and_executing_example_graph.png rename to docs/_static/basics/compiling_and_executing_example_graph.png diff --git a/frontends/concrete-python/docs/_static/compilation-pipeline/two_x_plus_three.png b/docs/_static/compilation-pipeline/two_x_plus_three.png similarity index 100% rename from frontends/concrete-python/docs/_static/compilation-pipeline/two_x_plus_three.png rename to docs/_static/compilation-pipeline/two_x_plus_three.png diff --git a/frontends/concrete-python/docs/_static/float_fusing_example/after.png b/docs/_static/float_fusing_example/after.png similarity index 100% rename from frontends/concrete-python/docs/_static/float_fusing_example/after.png rename to docs/_static/float_fusing_example/after.png diff --git a/frontends/concrete-python/docs/_static/float_fusing_example/after_bigger_search.png b/docs/_static/float_fusing_example/after_bigger_search.png similarity index 100% rename from frontends/concrete-python/docs/_static/float_fusing_example/after_bigger_search.png rename to docs/_static/float_fusing_example/after_bigger_search.png diff --git a/frontends/concrete-python/docs/_static/float_fusing_example/before.png b/docs/_static/float_fusing_example/before.png similarity index 100% rename from frontends/concrete-python/docs/_static/float_fusing_example/before.png rename to docs/_static/float_fusing_example/before.png diff --git a/frontends/concrete-python/docs/_static/float_fusing_example/before_bigger_search.png b/docs/_static/float_fusing_example/before_bigger_search.png similarity index 100% rename from frontends/concrete-python/docs/_static/float_fusing_example/before_bigger_search.png rename to docs/_static/float_fusing_example/before_bigger_search.png diff --git a/frontends/concrete-python/docs/_static/float_fusing_example/subgraph.png b/docs/_static/float_fusing_example/subgraph.png similarity index 100% rename from frontends/concrete-python/docs/_static/float_fusing_example/subgraph.png rename to docs/_static/float_fusing_example/subgraph.png diff --git a/frontends/concrete-python/docs/_static/float_fusing_example/subgraph_bigger_search.png b/docs/_static/float_fusing_example/subgraph_bigger_search.png similarity index 100% rename from frontends/concrete-python/docs/_static/float_fusing_example/subgraph_bigger_search.png rename to docs/_static/float_fusing_example/subgraph_bigger_search.png diff --git a/frontends/concrete-python/docs/_static/mlir/MLIR_conversion.png b/docs/_static/mlir/MLIR_conversion.png similarity index 100% rename from frontends/concrete-python/docs/_static/mlir/MLIR_conversion.png rename to docs/_static/mlir/MLIR_conversion.png diff --git a/frontends/concrete-python/docs/_static/p_error_simulation.pdf b/docs/_static/p_error_simulation.pdf similarity index 100% rename from frontends/concrete-python/docs/_static/p_error_simulation.pdf rename to docs/_static/p_error_simulation.pdf diff --git a/frontends/concrete-python/docs/_static/rounded-tlu/10-bits-removed.png b/docs/_static/rounded-tlu/10-bits-removed.png similarity index 100% rename from frontends/concrete-python/docs/_static/rounded-tlu/10-bits-removed.png rename to docs/_static/rounded-tlu/10-bits-removed.png diff --git a/frontends/concrete-python/docs/_static/rounded-tlu/12-bits-removed.png b/docs/_static/rounded-tlu/12-bits-removed.png similarity index 100% rename from frontends/concrete-python/docs/_static/rounded-tlu/12-bits-removed.png rename to docs/_static/rounded-tlu/12-bits-removed.png diff --git a/frontends/concrete-python/docs/_static/rounded-tlu/4-bits-kept.png b/docs/_static/rounded-tlu/4-bits-kept.png similarity index 100% rename from frontends/concrete-python/docs/_static/rounded-tlu/4-bits-kept.png rename to docs/_static/rounded-tlu/4-bits-kept.png diff --git a/frontends/concrete-python/docs/_static/rounded-tlu/6-bits-kept.png b/docs/_static/rounded-tlu/6-bits-kept.png similarity index 100% rename from frontends/concrete-python/docs/_static/rounded-tlu/6-bits-kept.png rename to docs/_static/rounded-tlu/6-bits-kept.png diff --git a/frontends/concrete-python/docs/_static/rounded-tlu/relu.png b/docs/_static/rounded-tlu/relu.png similarity index 100% rename from frontends/concrete-python/docs/_static/rounded-tlu/relu.png rename to docs/_static/rounded-tlu/relu.png diff --git a/frontends/concrete-python/docs/_static/tutorials/artifacts/manual/1.initial.graph.png b/docs/_static/tutorials/artifacts/manual/1.initial.graph.png similarity index 100% rename from frontends/concrete-python/docs/_static/tutorials/artifacts/manual/1.initial.graph.png rename to docs/_static/tutorials/artifacts/manual/1.initial.graph.png diff --git a/frontends/concrete-python/docs/_static/tutorials/artifacts/manual/2.after-fusing.graph.png b/docs/_static/tutorials/artifacts/manual/2.after-fusing.graph.png similarity index 100% rename from frontends/concrete-python/docs/_static/tutorials/artifacts/manual/2.after-fusing.graph.png rename to docs/_static/tutorials/artifacts/manual/2.after-fusing.graph.png diff --git a/frontends/concrete-python/docs/_static/tutorials/artifacts/manual/3.final.graph.png b/docs/_static/tutorials/artifacts/manual/3.final.graph.png similarity index 100% rename from frontends/concrete-python/docs/_static/tutorials/artifacts/manual/3.final.graph.png rename to docs/_static/tutorials/artifacts/manual/3.final.graph.png diff --git a/frontends/concrete-python/docs/_static/tutorials/table-lookup/1.initial.graph.png b/docs/_static/tutorials/table-lookup/1.initial.graph.png similarity index 100% rename from frontends/concrete-python/docs/_static/tutorials/table-lookup/1.initial.graph.png rename to docs/_static/tutorials/table-lookup/1.initial.graph.png diff --git a/frontends/concrete-python/docs/_static/tutorials/table-lookup/3.final.graph.png b/docs/_static/tutorials/table-lookup/3.final.graph.png similarity index 100% rename from frontends/concrete-python/docs/_static/tutorials/table-lookup/3.final.graph.png rename to docs/_static/tutorials/table-lookup/3.final.graph.png diff --git a/frontends/concrete-python/docs/_static/zama_home_docs.png b/docs/_static/zama_home_docs.png similarity index 70% rename from frontends/concrete-python/docs/_static/zama_home_docs.png rename to docs/_static/zama_home_docs.png index 02f23b7f811fc54fed4d7dc02014d98ab6770070..87e178f8cc07d7b7c850fac5ef53547878d63c44 100644 GIT binary patch delta 116371 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ð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

cbN;Fwrii0@S?j3KcVn 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 delta 117487 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 z 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 to the node of this input as `Encrypted` is the minimal encrypted integer that supports all values between `0` and `10`. +Let's say we have an encrypted input that is always between `0` and `10`. We should assign the type `EncryptedScalar` to the node of this input as `EncryptedScalar` is the minimal encrypted integer that supports all values between `0` and `10`. If there were negative values in the range, we could have used `intX` instead of `uintX`. @@ -137,12 +135,8 @@ New Bounds: Assigned Data Types: -* `x`: Encrypted<**uint2**> -* `2`: Clear<**uint2**> -* `*`: Encrypted<**uint3**> -* `3`: Clear<**uint2**> -* `+`: Encrypted<**uint4**> - -## MLIR conversion - -The actual compilation will be done by the **Concrete-Compiler**, which is expecting an MLIR input. The MLIR conversion goes from a computation graph to its MLIR equivalent. You can read more about it [here](mlir.md). +* `x`: EncryptedScalar<**uint2**> +* `2`: ClearScalar<**uint2**> +* `*`: EncryptedScalar<**uint3**> +* `3`: ClearScalar<**uint2**> +* `+`: EncryptedScalar<**uint4**> diff --git a/docs/dev/contributing.md b/docs/dev/contributing.md new file mode 100644 index 000000000..d8360dc71 --- /dev/null +++ b/docs/dev/contributing.md @@ -0,0 +1,6 @@ +# Contribute + +There are two ways to contribute to **Concrete**: + +* You can open issues to report bugs and typos and to suggest ideas. +* You can ask to become an official contributor by emailing hello@zama.ai. Only approved contributors can send pull requests (PRs), so please make sure to get in touch before you do! diff --git a/docs/dev/fusing.md b/docs/dev/fusing.md new file mode 100644 index 000000000..39d31869f --- /dev/null +++ b/docs/dev/fusing.md @@ -0,0 +1,33 @@ +# Fusing + +Fusing is the act of combining multiple nodes into a single node, which is converted to a table lookup. + +## How is it done? + +Code related to fusing is in the `frontends/concrete-python/concrete/fhe/compilation/utils.py` file. Fusing can be performed using the `fuse` function. + +Within `fuse`: + +1. We loop until there are no more subgraphs to fuse. +2. Within each iteration: + 2.1. We find a subgraph to fuse. + + 2.2. We search for a terminal node that is appropriate for fusing. + + 2.3. We crawl backwards to find the closest integer nodes to this node. + + 2.4. If there is a single node as such, we return the subgraph from this node to the terminal node. + + 2.5. Otherwise, we try to find the lowest common ancestor (lca) of this list of nodes. + + 2.6. If an lca doesn't exist, we say this particular terminal node is not fusable, and we go back to search for another subgraph. + + 2.7. Otherwise, we use this lca as the input of the subgraph and continue with `subgraph` node creation below. + + 2.8. We convert the subgraph into a `subgraph` node by checking fusability status of the nodes of the subgraph in this step. + + 2.9. We substitute the `subgraph` node to the original graph. + +## Limitations + +With the current implementation, we cannot fuse subgraphs that depend on multiple encrypted values where those values don't have a common lca (e.g., `np.round(np.sin(x) + np.cos(y))`). diff --git a/frontends/concrete-python/docs/dev/releasing.md b/docs/dev/releasing.md similarity index 91% rename from frontends/concrete-python/docs/dev/releasing.md rename to docs/dev/releasing.md index f92efa8d7..03d8792d5 100644 --- a/frontends/concrete-python/docs/dev/releasing.md +++ b/docs/dev/releasing.md @@ -2,7 +2,7 @@ ## Release candidate cycle -Throughout the quarter, many release candidatess are relesed. Those candidates are released in a private package repository. At the end of the quarter, we take the latest release candidate, and release it in PyPI without `rcX` tag. +Throughout the quarter, many release candidates are released. Those candidates are released in a private package repository. At the end of the quarter, we take the latest release candidate, and release it in PyPI without `rcX` tag. ## Release flow diff --git a/docs/dev/terminology_and_structure.md b/docs/dev/terminology_and_structure.md new file mode 100644 index 000000000..7e2844a46 --- /dev/null +++ b/docs/dev/terminology_and_structure.md @@ -0,0 +1,24 @@ +# Terminology and Structure + +## Terminology + +Some terms used throughout the project include: + +* computation graph: a data structure to represent a computation. This is basically a directed acyclic graph in which nodes are either inputs, constants or operations on other nodes. +* tracing: a technique that takes a python function from the user and generates a corresponding computation graph +* bounds: before computation graphs are converted to MLIR, we need to know which value should have which type (e.g., uint3 vs int5). we use inputsets to do that. we simulate the graph with the inputs in the inputset to remember the minimum and the maximum value for each node, which is what we call bounds, and use bounds to determine the appropriate type for each node. +* circuit: the result of compilation. a circuit is made of the client and server components. it has methods for everything from printing to evaluation. + +## Module structure + +In this section, we will briefly discuss the module structure of **Concrete-Python**. You are encouraged to check individual `.py` files to learn more. + +* concrete + * fhe + * dtypes: data type specifications (e.g., int4, uint5, float32) + * values: value specifications (i.e., data type + shape + encryption status) + * representation: representation of computation (e.g., computation graphs, nodes) + * tracing: tracing of python functions + * extensions: custom functionality (see [Extensions](../tutorial/extensions.md)) + * mlir: computation graph to mlir conversion + * compilation: configuration, compiler, artifacts, circuit, client/server, and anything else related to compilation diff --git a/frontends/concrete-python/docs/getting-started/compatibility.md b/docs/getting-started/compatibility.md similarity index 100% rename from frontends/concrete-python/docs/getting-started/compatibility.md rename to docs/getting-started/compatibility.md diff --git a/frontends/concrete-python/docs/getting-started/exactness.md b/docs/getting-started/exactness.md similarity index 72% rename from frontends/concrete-python/docs/getting-started/exactness.md rename to docs/getting-started/exactness.md index 18d6afe9e..d9728e305 100644 --- a/frontends/concrete-python/docs/getting-started/exactness.md +++ b/docs/getting-started/exactness.md @@ -1,6 +1,6 @@ # Exactness -One of the most common operations in **Concrete-Numpy** is `Table Lookups` (TLUs). TLUs are performed with an FHE operation called `Programmable Bootstrapping` (PBS). PBSes have a certain probability of error, which, when triggered, result in inaccurate results. +One of the most common operations in **Concrete** is `Table Lookups` (TLUs). TLUs are performed with an FHE operation called `Programmable Bootstrapping` (PBS). PBSes have a certain probability of error, which, when triggered, result in inaccurate results. Let's say you have the table: @@ -8,7 +8,7 @@ Let's say you have the table: [0, 1, 4, 9, 16, 25, 36, 49, 64] ``` -And you performed a table lookup using `4`. The result you should get is `16`, but because of the possibility of error, you can sometimes get `9` or `25`. Sometimes even `4` or `36` if you have a high probability of error. +And you performed a table lookup using `4`. The result you should get is `16`, but because of the possibility of error, you can get any other value in the table. The probability of this error can be configured through the `p_error` and `global_p_error` configuration options. The difference between these two options is that, `p_error` is for individual TLUs but `global_p_error` is for the whole circuit. @@ -18,10 +18,10 @@ However, if you set `global_p_error` to `0.01`, the whole circuit will have 1% p If you set both of them, both will be satisfied. Essentially, the stricter one will be used. -By default, both `p_error` and `global_p_error` is set to `None`, which results in `global_p_error` of `1 / 100_000` being used. Feel free to play with these configuration options to pick the one best suited for your needs! For example, in some machine learning use cases, off-by-one or off-by-two errors doesn't affect the result much, in such cases `p_error` could be set to increase performance without losing accuracy. +By default, both `p_error` and `global_p_error` is set to `None`, which results in `global_p_error` of `1 / 100_000` being used. Feel free to play with these configuration options to pick the one best suited for your needs! See [How to Configure](../howto/configure.md) to learn how you can set a custom `p_error` and/or `global_p_error`. {% hint style="info" %} -Configuring either of those variables would affect computation time (compilation, keys generation, circuit execution) and space requirements (size of the keys on disk and in memory). Lower error probability would result in longer computation time and larger space requirements. +Configuring either of those variables would affect computation time (compilation, keys generation, circuit execution) and space requirements (size of the keys on disk and in memory). Lower error probability would result in longer computation time and larger space requirements. {% endhint %} diff --git a/docs/getting-started/installing.md b/docs/getting-started/installing.md new file mode 100644 index 000000000..3d0cfeaf6 --- /dev/null +++ b/docs/getting-started/installing.md @@ -0,0 +1,21 @@ +# Installation + +**Concrete** is natively supported on Linux and macOS from Python 3.8 to 3.10 inclusive, but if you have Docker in your platform, you can use the docker image to use **Concrete**. + +## Using PyPI + +You can install **Concrete** from PyPI: + +```shell +pip install -U pip wheel setuptools +pip install concrete-python +``` + +## Using Docker + +You can also get the **Concrete** docker image: + +```shell +docker pull zamafhe/concrete-python:v1.0.0 +docker run --rm -it zamafhe/concrete-python:latest /bin/bash +``` diff --git a/docs/getting-started/performance.md b/docs/getting-started/performance.md new file mode 100644 index 000000000..34ac3acd9 --- /dev/null +++ b/docs/getting-started/performance.md @@ -0,0 +1,35 @@ +# Performance + +One of the most common operations in **Concrete** is `Table Lookups` (TLUs). All operations except addition, subtraction, multiplication with non-encrypted values, tensor manipulation operations, and a few operations built with those primitive operations (e.g. matmul, conv) are converted to table lookups under the hood: + +```python +from concrete import fhe + +@fhe.compiler({"x": "encrypted"}) +def f(x): + return x ** 2 + +inputset = range(2 ** 4) +circuit = f.compile(inputset) +``` + +is exactly the same as + +```python +from concrete import fhe + +table = fhe.LookupTable([x ** 2 for x in range(2 ** 4)]) + +@fhe.compiler({"x": "encrypted"}) +def f(x): + return table[x] + +inputset = range(2 ** 4) +circuit = f.compile(inputset) +``` + +Table lookups are very flexible! They allow Concrete to support many operations, but they are expensive. The exact cost depends on many variables (hardware used, error probability, etc.) but they are always much more expensive compared to other operations. Therefore, you should try to avoid them as much as possible. In most cases, it's not possible to avoid them completely, but you might remove the number of TLUs or replace some of them with other primitive operations. + +{% hint style="info" %} +Concrete automatically parallelize TLUs if they are applied to tensors. +{% endhint %} diff --git a/frontends/concrete-python/docs/getting-started/quick_start.md b/docs/getting-started/quick_start.md similarity index 87% rename from frontends/concrete-python/docs/getting-started/quick_start.md rename to docs/getting-started/quick_start.md index efc073a99..8c9be1131 100644 --- a/frontends/concrete-python/docs/getting-started/quick_start.md +++ b/docs/getting-started/quick_start.md @@ -1,16 +1,16 @@ # Quick Start -To compute on encrypted data, you first need to define the function that you want to compute, then compile it into a Concrete-Numpy `Circuit`, which you can use to perform homomorphic evaluation. +To compute on encrypted data, you first need to define the function that you want to compute, then compile it into a Concrete `Circuit`, which you can use to perform homomorphic evaluation. Here is the full example that we will walk through: ```python -import concrete.numpy as cnp +from concrete import fhe def add(x, y): return x + y -compiler = cnp.Compiler(add, {"x": "encrypted", "y": "clear"}) +compiler = fhe.Compiler(add, {"x": "encrypted", "y": "clear"}) inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1)] circuit = compiler.compile(inputset) @@ -30,7 +30,7 @@ Everything you need to perform homomorphic evaluation is included in a single mo ```python -import concrete.numpy as cnp +from concrete import fhe ``` ## Defining the function to compile @@ -49,7 +49,7 @@ To compile the function, you need to create a `Compiler` by specifying the funct ```python -compiler = cnp.Compiler(add, {"x": "encrypted", "y": "clear"}) +compiler = fhe.Compiler(add, {"x": "encrypted", "y": "clear"}) ``` ## Defining an inputset diff --git a/frontends/concrete-python/docs/howto/configure.md b/docs/howto/configure.md similarity index 74% rename from frontends/concrete-python/docs/howto/configure.md rename to docs/howto/configure.md index 286b5a4e2..a8262733e 100644 --- a/frontends/concrete-python/docs/howto/configure.md +++ b/docs/howto/configure.md @@ -1,14 +1,14 @@ # Configure -The behavior of **Concrete-Numpy** can be customized using `Configuration`s: +The behavior of **Concrete** can be customized using `Configuration`s: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -configuration = cnp.Configuration(p_error=0.01, loop_parallelize=True) +configuration = fhe.Configuration(p_error=0.01, dataflow_parallelize=True) -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return x + 42 @@ -19,26 +19,26 @@ circuit = f.compile(inputset, configuration=configuration) Alternatively, you can overwrite individual options as kwargs to `compile` method: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return x + 42 inputset = range(10) -circuit = f.compile(inputset, p_error=0.01, loop_parallelize=True) +circuit = f.compile(inputset, p_error=0.01, dataflow_parallelize=True) ``` Or you can combine both: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -configuration = cnp.Configuration(p_error=0.01) +configuration = fhe.Configuration(p_error=0.01) -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return x + 42 @@ -66,18 +66,21 @@ Additional kwarg to `compile` function have higher precedence. So if you set an * **verbose**: bool = False * Whether to print details related to compilation. - + * **dump\_artifacts\_on\_unexpected\_failures**: bool = True * Whether to export debugging artifacts automatically on compilation failures. -* **auto_adjust_rounders**: bool = False +* **auto\_adjust\_rounders**: bool = False * Whether to adjust rounders automatically. -* **p_error**: Optional[float] = None +* **p\_error**: Optional[float] = None * Error probability for individual table lookups. If set, all table lookups will have the probability of non-exact result smaller than the set value. See [Exactness](../getting-started/exactness.md) to learn more. -* **global_p_error**: Optional[float] = None - * Global error probability for the whole circuit. If set, the whole circuit will have the probability of non-exact result smaller than the set value. See [Exactness](../getting-started/exactness.md) to learn more. +* **global\_p\_error**: Optional[float] = None + * Global error probability for the whole circuit. If set, the whole circuit will have the probability of non-exact result smaller than the set value. See [Exactness](../getting-started/exactness.md) to learn more. + +* **single_precision**: bool = True + * Whether to use single precision for the whole circuit. * **jit**: bool = False * Whether to use JIT compilation. diff --git a/docs/howto/debug.md b/docs/howto/debug.md new file mode 100644 index 000000000..c4c0aca4f --- /dev/null +++ b/docs/howto/debug.md @@ -0,0 +1,305 @@ +# Debug + +In this section, you will learn how to debug the compilation process easily as well as how to get help in case you cannot resolve your issue. + +## Debug Artifacts + +**Concrete** has an artifact system to simplify the process of debugging issues. + +### Automatic export. + +In case of compilation failures, artifacts are exported automatically to the `.artifacts` directory under the working directory. Let's intentionally create a compilation failure to show what kinds of things are exported. + +```python +def f(x): + return np.sin(x) +``` + +This function fails to compile because **Concrete** does not support floating-point outputs. When you try to compile it, an exception will be raised and the artifacts will be exported automatically. If you go the `.artifacts` directory under the working directory, you'll see the following files: + +#### environment.txt + +This file contains information about your setup (i.e., your operating system and python version). + +``` +Linux-5.12.13-arch1-2-x86_64-with-glibc2.29 #1 SMP PREEMPT Fri, 25 Jun 2021 22:56:51 +0000 +Python 3.8.10 +``` + +#### requirements.txt + +This file contains information about python packages and their versions installed on your system. + +``` +astroid==2.15.0 +attrs==22.2.0 +auditwheel==5.3.0 +... +wheel==0.40.0 +wrapt==1.15.0 +zipp==3.15.0 +``` + +#### function.txt + +This file contains information about the function you tried to compile. + +``` +def f(x): + return np.sin(x) +``` + +#### parameters.txt + +This file contains information about the encryption status of the parameters of the function you tried to compile. + +``` +x :: encrypted +``` + +#### 1.initial.graph.txt + +This file contains the textual representation of the initial computation graph right after tracing. + +``` +%0 = x # EncryptedScalar +%1 = sin(%0) # EncryptedScalar +return %1 +``` + +#### 2.final.graph.txt + +This file contains the textual representation of the final computation graph right before MLIR conversion. + +``` +%0 = x # EncryptedScalar +%1 = sin(%0) # EncryptedScalar +return %1 +``` + +#### traceback.txt + +This file contains information about the error you received. + +``` +Traceback (most recent call last): + File "/path/to/your/script.py", line 9, in + circuit = f.compile(inputset) + File "/usr/local/lib/python3.10/site-packages/concrete/fhe/compilation/decorators.py", line 159, in compile + return self.compiler.compile(inputset, configuration, artifacts, **kwargs) + File "/usr/local/lib/python3.10/site-packages/concrete/fhe/compilation/compiler.py", line 437, in compile + mlir = GraphConverter.convert(self.graph) + File "/usr/local/lib/python3.10/site-packages/concrete/fhe/mlir/graph_converter.py", line 677, in convert + GraphConverter._check_graph_convertibility(graph) + File "/usr/local/lib/python3.10/site-packages/concrete/fhe/mlir/graph_converter.py", line 240, in _check_graph_convertibility + raise RuntimeError(message) +RuntimeError: Function you are trying to compile cannot be converted to MLIR + +%0 = x # EncryptedScalar ∈ [3, 5] +%1 = sin(%0) # EncryptedScalar ∈ [-0.958924, 0.14112] +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ only integer operations are supported + /path/to/your/script.py:6 +return %1 +``` + +### Manual export. + +Manual exports are mostly used for visualization. Nonetheless, they can be very useful for demonstrations. Here is how to perform one: + +```python +from concrete import fhe +import numpy as np + +artifacts = fhe.DebugArtifacts("/tmp/custom/export/path") + +@fhe.compiler({"x": "encrypted"}) +def f(x): + return 127 - (50 * (np.sin(x) + 1)).astype(np.int64) + +inputset = range(2 ** 3) +circuit = f.compile(inputset, artifacts=artifacts) + +artifacts.export() +``` + +If you go to the `/tmp/custom/export/path` directory, you'll see the following files: + +#### 1.initial.graph.txt + +This file contains the textual representation of the initial computation graph right after tracing. + +``` +%0 = x # EncryptedScalar +%1 = sin(%0) # EncryptedScalar +%2 = 1 # ClearScalar +%3 = add(%1, %2) # EncryptedScalar +%4 = 50 # ClearScalar +%5 = multiply(%4, %3) # EncryptedScalar +%6 = astype(%5, dtype=int_) # EncryptedScalar +%7 = 127 # ClearScalar +%8 = subtract(%7, %6) # EncryptedScalar +return %8 +``` + +#### 2.after-fusing.graph.txt + +This file contains the textual representation of the intermediate computation graph after fusing. + +``` +%0 = x # EncryptedScalar +%1 = subgraph(%0) # EncryptedScalar +%2 = 127 # ClearScalar +%3 = subtract(%2, %1) # EncryptedScalar +return %3 + +Subgraphs: + + %1 = subgraph(%0): + + %0 = input # EncryptedScalar + %1 = sin(%0) # EncryptedScalar + %2 = 1 # ClearScalar + %3 = add(%1, %2) # EncryptedScalar + %4 = 50 # ClearScalar + %5 = multiply(%4, %3) # EncryptedScalar + %6 = astype(%5, dtype=int_) # EncryptedScalar + return %6 +``` + +#### 3.final.graph.txt + +This file contains the textual representation of the final computation graph right before MLIR conversion. + +``` +%0 = x # EncryptedScalar ∈ [0, 7] +%1 = subgraph(%0) # EncryptedScalar ∈ [2, 95] +%2 = 127 # ClearScalar ∈ [127, 127] +%3 = subtract(%2, %1) # EncryptedScalar ∈ [32, 125] +return %3 + +Subgraphs: + + %1 = subgraph(%0): + + %0 = input # EncryptedScalar + %1 = sin(%0) # EncryptedScalar + %2 = 1 # ClearScalar + %3 = add(%1, %2) # EncryptedScalar + %4 = 50 # ClearScalar + %5 = multiply(%4, %3) # EncryptedScalar + %6 = astype(%5, dtype=int_) # EncryptedScalar + return %6 +``` + +#### mlir.txt + +This file contains information about the MLIR of the function you compiled using the inputset you provided. + +``` +module { + func.func @main(%arg0: !FHE.eint<7>) -> !FHE.eint<7> { + %c127_i8 = arith.constant 127 : i8 + %cst = arith.constant dense<"..."> : tensor<128xi64> + %0 = "FHE.apply_lookup_table"(%arg0, %cst) : (!FHE.eint<7>, tensor<128xi64>) -> !FHE.eint<7> + %1 = "FHE.sub_int_eint"(%c127_i8, %0) : (i8, !FHE.eint<7>) -> !FHE.eint<7> + return %1 : !FHE.eint<7> + } +} +``` + +#### client_parameters.json + +This file contains information about the client parameters chosen by **Concrete**. + +``` +{ + "bootstrapKeys": [ + { + "baseLog": 22, + "glweDimension": 1, + "inputLweDimension": 908, + "inputSecretKeyID": 1, + "level": 1, + "outputSecretKeyID": 0, + "polynomialSize": 8192, + "variance": 4.70197740328915e-38 + } + ], + "functionName": "main", + "inputs": [ + { + "encryption": { + "encoding": { + "isSigned": false, + "precision": 7 + }, + "secretKeyID": 0, + "variance": 4.70197740328915e-38 + }, + "shape": { + "dimensions": [], + "sign": false, + "size": 0, + "width": 7 + } + } + ], + "keyswitchKeys": [ + { + "baseLog": 3, + "inputSecretKeyID": 0, + "level": 6, + "outputSecretKeyID": 1, + "variance": 1.7944329123150665e-13 + } + ], + "outputs": [ + { + "encryption": { + "encoding": { + "isSigned": false, + "precision": 7 + }, + "secretKeyID": 0, + "variance": 4.70197740328915e-38 + }, + "shape": { + "dimensions": [], + "sign": false, + "size": 0, + "width": 7 + } + } + ], + "packingKeyswitchKeys": [], + "secretKeys": [ + { + "dimension": 8192 + }, + { + "dimension": 908 + } + ] +} +``` + +## Asking the community + +You can seek help with your issue by asking a question directly in the [community forum](https://community.zama.ai/). + +## Submitting an issue + +If you cannot find a solution in the community forum, or you found a bug in the library, you could create an issue in our GitHub repository. + +In case of a bug: + +* try to minimize randomness +* try to minimize your function as much as possible while keeping the bug - this will help to fix the bug faster +* try to include your inputset in the issue +* try to include reproduction steps in the issue +* try to include debug artifacts in the issue + +In case of a feature request: + +* try to give a minimal example of the desired behavior +* try to explain your use case diff --git a/frontends/concrete-python/docs/howto/deploy.md b/docs/howto/deploy.md similarity index 91% rename from frontends/concrete-python/docs/howto/deploy.md rename to docs/howto/deploy.md index e7cae7e5f..b3a966d97 100644 --- a/frontends/concrete-python/docs/howto/deploy.md +++ b/docs/howto/deploy.md @@ -1,6 +1,6 @@ # Deploy -After developing your circuit, you may want to deploy it. However, sharing the details of your circuit with every client might not be desirable. Further, you might want to perform the computation in dedicated servers. In this case, you can use the `Client` and `Server` features of **Concrete-Numpy**. +After developing your circuit, you may want to deploy it. However, sharing the details of your circuit with every client might not be desirable. Further, you might want to perform the computation in dedicated servers. In this case, you can use the `Client` and `Server` features of **Concrete**. ## Development of the circuit @@ -8,9 +8,9 @@ You can develop your circuit like we've discussed in the previous chapters. Here ```python -import concrete.numpy as cnp +from concrete import fhe -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def function(x): return x + 42 @@ -33,9 +33,9 @@ You can load the `server.zip` you get from the development machine as follows: ```python -import concrete.numpy as cnp +from concrete import fhe -server = cnp.Server.load("server.zip") +server = fhe.Server.load("server.zip") ``` At this point, you will need to wait for requests from clients. The first likely request is for `ClientSpecs`. @@ -55,8 +55,8 @@ After getting the serialized `ClientSpecs` from a server, you can create the cli ```python -client_specs = cnp.ClientSpecs.deserialize(serialized_client_specs) -client = cnp.Client(client_specs) +client_specs = fhe.ClientSpecs.deserialize(serialized_client_specs) +client = fhe.Client(client_specs) ``` ## Generating keys (on the client) @@ -100,7 +100,7 @@ Upon having the serialized evaluation keys and serialized arguments, you can des ```python -deserialized_evaluation_keys = cnp.EvaluationKeys.deserialize(serialized_evaluation_keys) +deserialized_evaluation_keys = fhe.EvaluationKeys.deserialize(serialized_evaluation_keys) deserialized_args = server.client_specs.deserialize_public_args(serialized_args) ``` diff --git a/frontends/concrete-python/docs/tutorial/decorator.md b/docs/tutorial/decorator.md similarity index 88% rename from frontends/concrete-python/docs/tutorial/decorator.md rename to docs/tutorial/decorator.md index c46ca92ab..923e5eedc 100644 --- a/frontends/concrete-python/docs/tutorial/decorator.md +++ b/docs/tutorial/decorator.md @@ -3,9 +3,9 @@ If you are trying to compile a regular function, you can use the decorator interface instead of the explicit `Compiler` interface to simplify your code: ```python -import concrete.numpy as cnp +from concrete import fhe -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return x + 42 diff --git a/frontends/concrete-python/docs/tutorial/direct_circuits.md b/docs/tutorial/direct_circuits.md similarity index 82% rename from frontends/concrete-python/docs/tutorial/direct_circuits.md rename to docs/tutorial/direct_circuits.md index 53e0b7ef0..ea2afe2f9 100644 --- a/frontends/concrete-python/docs/tutorial/direct_circuits.md +++ b/docs/tutorial/direct_circuits.md @@ -7,10 +7,10 @@ Direct circuits are still experimental, and it's very easy to shoot yourself in For some applications, data types of inputs, intermediate values and outputs are known (e.g., for manipulating bytes, you would want to use uint8). For such cases, using inputsets to determine bounds are not necessary, or even error-prone. Therefore, another interface for defining such circuits, is introduced: ```python -import concrete.numpy as cnp +from concrete import fhe -@cnp.circuit({"x": "encrypted"}) -def circuit(x: cnp.uint8): +@fhe.circuit({"x": "encrypted"}) +def circuit(x: fhe.uint8): return x + 42 assert circuit.encrypt_run_decrypt(10) == 52 @@ -18,27 +18,27 @@ assert circuit.encrypt_run_decrypt(10) == 52 There are a few differences between direct circuits and traditional circuits though: -- You need to remember that resulting dtype for each operation will be determined by its inputs. This can lead to some unexpected results if you're not careful (e.g., if you do `-x` where `x: cnp.uint8`, you'll not get the negative value as the result will be `cnp.uint8` as well) -- You need to use cnp types in `.astype(...)` calls (e.g., `np.sqrt(x).astype(cnp.uint4)`). This is because there are no inputset evaluation, so cannot determine the bit-width of the output. -- You need to specify the resulting data type in [univariate](./extensions.md#cnpunivariatefunction) extension (e.g., `cnp.univariate(function, outputs=cnp.uint4)(x)`), because of the same reason as above. +- You need to remember that resulting dtype for each operation will be determined by its inputs. This can lead to some unexpected results if you're not careful (e.g., if you do `-x` where `x: fhe.uint8`, you'll not get the negative value as the result will be `fhe.uint8` as well) +- You need to use fhe types in `.astype(...)` calls (e.g., `np.sqrt(x).astype(fhe.uint4)`). This is because there are no inputset evaluation, so cannot determine the bit-width of the output. +- You need to specify the resulting data type in [univariate](./extensions.md#fheunivariatefunction) extension (e.g., `fhe.univariate(function, outputs=fhe.uint4)(x)`), because of the same reason as above. - You need to be careful with overflows. With inputset evaluation, you'll get bigger bit-widths but no overflows, with direct definition, you're responsible to ensure there aren't any overflows! Let's go over a more complicated example to see how direct circuits behave: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np def square(value): return value ** 2 -@cnp.circuit({"x": "encrypted", "y": "encrypted"}) -def circuit(x: cnp.uint8, y: cnp.int2): +@fhe.circuit({"x": "encrypted", "y": "encrypted"}) +def circuit(x: fhe.uint8, y: fhe.int2): a = x + 10 b = y + 10 - c = np.sqrt(a).round().astype(cnp.uint4) - d = cnp.univariate(square, outputs=cnp.uint8)(b) + c = np.sqrt(a).round().astype(fhe.uint4) + d = fhe.univariate(square, outputs=fhe.uint8)(b) return d - c diff --git a/docs/tutorial/extensions.md b/docs/tutorial/extensions.md new file mode 100644 index 000000000..a76887219 --- /dev/null +++ b/docs/tutorial/extensions.md @@ -0,0 +1,205 @@ +# Extensions + +**Concrete** tries to support native Python and NumPy operations as much as possible, but not everything is available in Python or NumPy. So, we provide some extensions ourselves to improve your experience. + +## fhe.univariate(function) + +Allows you to wrap any univariate function into a single table lookup: + +```python +import numpy as np +from concrete import fhe + +def complex_univariate_function(x): + + def per_element(element): + result = 0 + for i in range(element): + result += i + return result + + return np.vectorize(per_element)(x) + +@fhe.compiler({"x": "encrypted"}) +def f(x): + return fhe.univariate(complex_univariate_function)(x) + +inputset = [np.random.randint(0, 5, size=(3, 2)) for _ in range(10)] +circuit = f.compile(inputset) + +sample = np.array([ + [0, 4], + [2, 1], + [3, 0], +]) +assert np.array_equal(circuit.encrypt_run_decrypt(sample), complex_univariate_function(sample)) +``` + +{% hint style="danger" %} +The wrapped function shouldn't have any side effects, and it should be deterministic. Otherwise, the outcome is undefined. +{% endhint %} + +## fhe.conv(...) + +Allows you to perform convolution operation, with the same semantic of [onnx.Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#conv): + +```python +import numpy as np +from concrete import fhe + +weight = np.array([[2, 1], [3, 2]]).reshape(1, 1, 2, 2) + +@fhe.compiler({"x": "encrypted"}) +def f(x): + return fhe.conv(x, weight, strides=(2, 2), dilations=(1, 1), group=1) + +inputset = [np.random.randint(0, 4, size=(1, 1, 4, 4)) for _ in range(10)] +circuit = f.compile(inputset) + +sample = np.array( + [ + [3, 2, 1, 0], + [3, 2, 1, 0], + [3, 2, 1, 0], + [3, 2, 1, 0], + ] +).reshape(1, 1, 4, 4) +assert np.array_equal(circuit.encrypt_run_decrypt(sample), f(sample)) +``` + +{% hint style="danger" %} +Only 2D convolutions without padding and with one groups are supported for the time being. +{% endhint %} + +## fhe.maxpool(...) + +Allows you to perform maxpool operation, with the same semantic of [onnx.MaxPool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#maxpool): + +```python +import numpy as np +from concrete import fhe + +@fhe.compiler({"x": "encrypted"}) +def f(x): + return fhe.maxpool(x, kernel_shape=(2, 2), strides=(2, 2), dilations=(1, 1)) + +inputset = [np.random.randint(0, 4, size=(1, 1, 4, 4)) for _ in range(10)] +circuit = f.compile(inputset) + +sample = np.array( + [ + [3, 2, 1, 0], + [3, 2, 1, 0], + [3, 2, 1, 0], + [3, 2, 1, 0], + ] +).reshape(1, 1, 4, 4) +assert np.array_equal(circuit.encrypt_run_decrypt(sample), f(sample)) +``` + +{% hint style="danger" %} +Only 2D maxpooling without padding up to 15-bits is supported for the time being. +{% endhint %} + +## fhe.array(...) + +Allows you to create encrypted arrays: + +```python +import numpy as np +from concrete import fhe + +@fhe.compiler({"x": "encrypted", "y": "encrypted"}) +def f(x, y): + return fhe.array([x, y]) + +inputset = [(3, 2), (7, 0), (0, 7), (4, 2)] +circuit = f.compile(inputset) + +sample = (3, 4) +assert np.array_equal(circuit.encrypt_run_decrypt(*sample), f(*sample)) +``` + +{% hint style="danger" %} +Only scalars can be used to create arrays for the time being. +{% endhint %} + +## fhe.zero() + +Allows you to create encrypted scalar zero: + +```python +from concrete import fhe +import numpy as np + +@fhe.compiler({"x": "encrypted"}) +def f(x): + z = fhe.zero() + return x + z + +inputset = range(10) +circuit = f.compile(inputset) + +for x in range(10): + assert circuit.encrypt_run_decrypt(x) == x +``` + +## fhe.zeros(shape) + +Allows you to create encrypted tensor of zeros: + +```python +from concrete import fhe +import numpy as np + +@fhe.compiler({"x": "encrypted"}) +def f(x): + z = fhe.zeros((2, 3)) + return x + z + +inputset = range(10) +circuit = f.compile(inputset) + +for x in range(10): + assert np.array_equal(circuit.encrypt_run_decrypt(x), np.array([[x, x, x], [x, x, x]])) +``` + +## fhe.one() + +Allows you to create encrypted scalar one: + +```python +from concrete import fhe +import numpy as np + +@fhe.compiler({"x": "encrypted"}) +def f(x): + z = fhe.one() + return x + z + +inputset = range(10) +circuit = f.compile(inputset) + +for x in range(10): + assert circuit.encrypt_run_decrypt(x) == x + 1 +``` + +## fhe.ones(shape) + +Allows you to create encrypted tensor of ones: + +```python +from concrete import fhe +import numpy as np + +@fhe.compiler({"x": "encrypted"}) +def f(x): + z = fhe.ones((2, 3)) + return x + z + +inputset = range(10) +circuit = f.compile(inputset) + +for x in range(10): + assert np.array_equal(circuit.encrypt_run_decrypt(x), np.array([[x, x, x], [x, x, x]]) + 1) +``` diff --git a/frontends/concrete-python/docs/tutorial/floating_points.md b/docs/tutorial/floating_points.md similarity index 83% rename from frontends/concrete-python/docs/tutorial/floating_points.md rename to docs/tutorial/floating_points.md index 0ce7281fc..4fb07a0d5 100644 --- a/frontends/concrete-python/docs/tutorial/floating_points.md +++ b/docs/tutorial/floating_points.md @@ -1,6 +1,6 @@ # Floating Points -**Concrete-Numpy** partly supports floating points: +**Concrete** partly supports floating points: * They cannot be inputs * They cannot be outputs @@ -10,13 +10,13 @@ **Concrete-Compile**, which is used for compiling the circuit, doesn't support floating points at all. However, it supports table lookups. They take an integer and map it to another integer. It does not care how the lookup table is calculated. Further, the constraints of this operation are such that there should be a single integer input and it should result in a single integer output. -As long as your floating point operations comply with those constraints, **Concrete-Numpy** automatically converts your operations to a table lookup operation: +As long as your floating point operations comply with those constraints, **Concrete** automatically converts your operations to a table lookup operation: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): a = x + 1.5 b = np.sin(x) @@ -31,16 +31,16 @@ for x in range(8): assert circuit.encrypt_run_decrypt(x) == f(x) ``` -In the example above, `a`, `b`, and `c` are all floating point intermediates. However, they are just used to calculate `d`, which is an integer and value of `d` dependent upon `x` , which is another integer. **Concrete-Numpy** detects this and fuses all of those operations into a single table lookup from `x` to `d`. +In the example above, `a`, `b`, and `c` are all floating point intermediates. However, they are just used to calculate `d`, which is an integer and value of `d` dependent upon `x` , which is another integer. **Concrete** detects this and fuses all of those operations into a single table lookup from `x` to `d`. This approach works for a variety of use cases, but it comes up short for some: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -@cnp.compiler({"x": "encrypted", "y": "encrypted"}) +@fhe.compiler({"x": "encrypted", "y": "encrypted"}) def f(x, y): a = x + 1.5 b = np.sin(y) @@ -76,4 +76,4 @@ RuntimeError: Function you are trying to compile cannot be converted to MLIR return %7 ``` -The reason for this is that `d` no longer depends solely on `x`, it depends on `y` as well. **Concrete-Numpy** cannot fuse these operations, so it raises an exception instead. +The reason for this is that `d` no longer depends solely on `x`, it depends on `y` as well. **Concrete** cannot fuse these operations, so it raises an exception instead. diff --git a/frontends/concrete-python/docs/tutorial/formatting.md b/docs/tutorial/formatting.md similarity index 67% rename from frontends/concrete-python/docs/tutorial/formatting.md rename to docs/tutorial/formatting.md index 9b1e4d56f..d7042be92 100644 --- a/frontends/concrete-python/docs/tutorial/formatting.md +++ b/docs/tutorial/formatting.md @@ -15,5 +15,5 @@ print(circuit) ``` {% hint style="warning" %} -Formatting is just for debugging. It's not possible to serialize the circuit back from its textual representation. See [How to Deploy](../howto/deploy.md) if that's your goal. +Formatting is just for debugging. It's not possible to create the circuit back from its textual representation. See [How to Deploy](../howto/deploy.md) if that's your goal. {% endhint %} diff --git a/frontends/concrete-python/docs/tutorial/key_value_database.ipynb b/docs/tutorial/key_value_database.ipynb similarity index 100% rename from frontends/concrete-python/docs/tutorial/key_value_database.ipynb rename to docs/tutorial/key_value_database.ipynb diff --git a/frontends/concrete-python/docs/tutorial/key_value_database.md b/docs/tutorial/key_value_database.md similarity index 100% rename from frontends/concrete-python/docs/tutorial/key_value_database.md rename to docs/tutorial/key_value_database.md diff --git a/frontends/concrete-python/docs/tutorial/rounded_table_lookups.md b/docs/tutorial/rounded_table_lookups.md similarity index 88% rename from frontends/concrete-python/docs/tutorial/rounded_table_lookups.md rename to docs/tutorial/rounded_table_lookups.md index c2f266840..6cfbe4c38 100644 --- a/frontends/concrete-python/docs/tutorial/rounded_table_lookups.md +++ b/docs/tutorial/rounded_table_lookups.md @@ -1,14 +1,14 @@ # Rounded Table Lookups {% hint style="warning" %} -Rounded table lookups are not compilable yet. API is stable and will not change so it's documented, but you might not be able to run the code samples in this document. +Rounded table lookups are not compilable yet. API is stable and will not change, so it's documented, but you might not be able to run the code samples in this document. {% endhint %} Table lookups have a strict constraint on number of bits they support. This can be quite limiting, especially if you don't need the exact precision. To overcome such shortcomings, rounded table lookup operation is introduced. It's a way to extract most significant bits of a large integer and then applying the table lookup to those bits. -Imagine you have an 8-bit value, but you want to have a 5-bit table lookup, you can call `cnp.round_bit_pattern(input, lsbs_to_remove=3)` and use the value you get in the table lookup. +Imagine you have an 8-bit value, but you want to have a 5-bit table lookup, you can call `fhe.round_bit_pattern(input, lsbs_to_remove=3)` and use the value you get in the table lookup. In Python, evaluation will work like the following: ``` @@ -110,17 +110,17 @@ plt.show() Input range is [-100_000, 100_000), which means 18-bit table lookups are required, but they are not supported yet, you can apply rounding operation to the input before passing it to `ReLU` function: ```python -import concrete.numpy as cnp +from concrete import fhe import matplotlib.pyplot as plt import numpy as np def relu(x): return x if x >= 0 else 0 -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): - x = cnp.round_bit_pattern(x, lsbs_to_remove=10) - return cnp.univariate(relu)(x) + x = fhe.round_bit_pattern(x, lsbs_to_remove=10) + return fhe.univariate(relu)(x) inputset = [-100_000, (100_000 - 1)] circuit = f.compile(inputset) @@ -143,22 +143,22 @@ which is close enough to original ReLU for some cases. If your application is mo This is very useful, but in some cases, you don't know how many bits your input have, so it's not reliable to specify `lsbs_to_remove` manually. For this reason, `AutoRounder` class is introduced. ```python -import concrete.numpy as cnp +from concrete import fhe import matplotlib.pyplot as plt import numpy as np -rounder = cnp.AutoRounder(target_msbs=6) +rounder = fhe.AutoRounder(target_msbs=6) def relu(x): return x if x >= 0 else 0 -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): - x = cnp.round_bit_pattern(x, lsbs_to_remove=rounder) - return cnp.univariate(relu)(x) + x = fhe.round_bit_pattern(x, lsbs_to_remove=rounder) + return fhe.univariate(relu)(x) inputset = [-100_000, (100_000 - 1)] -cnp.AutoRounder.adjust(f, inputset) # alternatively, you can use `auto_adjust_rounders=True` below +fhe.AutoRounder.adjust(f, inputset) # alternatively, you can use `auto_adjust_rounders=True` below circuit = f.compile(inputset) xs = range(-100_000, 100_000) @@ -168,7 +168,7 @@ plt.plot(xs, ys) plt.show() ``` -`AutoRounder`s allow you to set how many of the most significant bits to keep, but they need to be adjusted using an inputset to determine how many of the least significant bits to remove. This can be done manually using `cnp.AutoRounder.adjust(function, inputset)`, or by setting `auto_adjust_rounders` to `True` during compilation. +`AutoRounder`s allow you to set how many of the most significant bits to keep, but they need to be adjusted using an inputset to determine how many of the least significant bits to remove. This can be done manually using `fhe.AutoRounder.adjust(function, inputset)`, or by setting `auto_adjust_rounders` to `True` during compilation. In the example above, `6` of the most significant bits are kept to get: diff --git a/frontends/concrete-python/docs/tutorial/simulation.md b/docs/tutorial/simulation.md similarity index 96% rename from frontends/concrete-python/docs/tutorial/simulation.md rename to docs/tutorial/simulation.md index 2558341b0..acc40d16e 100644 --- a/frontends/concrete-python/docs/tutorial/simulation.md +++ b/docs/tutorial/simulation.md @@ -6,10 +6,10 @@ You could call the function you're trying to compile directly of course, but it Considering these, simulation is introduced: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return (x + 1) ** 2 diff --git a/frontends/concrete-python/docs/tutorial/table_lookups.md b/docs/tutorial/table_lookups.md similarity index 76% rename from frontends/concrete-python/docs/tutorial/table_lookups.md rename to docs/tutorial/table_lookups.md index b8a926111..1c8cb61f3 100644 --- a/frontends/concrete-python/docs/tutorial/table_lookups.md +++ b/docs/tutorial/table_lookups.md @@ -1,10 +1,10 @@ # Table Lookups -In this tutorial, we will review the ways to perform direct table lookups in **Concrete-Numpy**. +In this tutorial, we will review the ways to perform direct table lookups in **Concrete**. ## Direct table lookup -**Concrete-Numpy** provides a `LookupTable` class for you to create your own tables and apply them in your circuits. +**Concrete** provides a `LookupTable` class for you to create your own tables and apply them in your circuits. {% hint style="info" %} `LookupTable`s can have any number of elements. Let's call them **N**. As long as the lookup variable is in range \[-**N**, **N**), table lookup is valid. @@ -16,20 +16,16 @@ IndexError: index 10 is out of bounds for axis 0 with size 6 ``` {% endhint %} -{% hint style="info" %} -The number of elements in the lookup table doesn't affect performance in any way. -{% endhint %} - ### With scalars. You can create the lookup table using a list of integers and apply it using indexing: ```python -import concrete.numpy as cnp +from concrete import fhe -table = cnp.LookupTable([2, -1, 3, 0]) +table = fhe.LookupTable([2, -1, 3, 0]) -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return table[x] @@ -47,12 +43,12 @@ assert circuit.encrypt_run_decrypt(3) == table[3] == 0 When you apply the table lookup to a tensor, you apply the scalar table lookup to each element of the tensor: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -table = cnp.LookupTable([2, -1, 3, 0]) +table = fhe.LookupTable([2, -1, 3, 0]) -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return table[x] @@ -79,11 +75,11 @@ for i in range(2): `LookupTable` mimics array indexing in Python, which means if the lookup variable is negative, the table is looked up from the back: ```python -import concrete.numpy as cnp +from concrete import fhe -table = cnp.LookupTable([2, -1, 3, 0]) +table = fhe.LookupTable([2, -1, 3, 0]) -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return table[-x] @@ -101,19 +97,19 @@ assert circuit.encrypt_run_decrypt(4) == table[-4] == 2 In case you want to apply a different lookup table to each element of a tensor, you can have a `LookupTable` of `LookupTable`s: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -squared = cnp.LookupTable([i ** 2 for i in range(4)]) -cubed = cnp.LookupTable([i ** 3 for i in range(4)]) +squared = fhe.LookupTable([i ** 2 for i in range(4)]) +cubed = fhe.LookupTable([i ** 3 for i in range(4)]) -table = cnp.LookupTable([ +table = fhe.LookupTable([ [squared, cubed], [squared, cubed], [squared, cubed], ]) -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return table[x] @@ -144,13 +140,13 @@ In this example, we applied a `squared` table to the first column and a `cubed` ## Fused table lookup -**Concrete-Numpy** tries to fuse some operations into table lookups automatically, so you don't need to create the lookup tables manually: +**Concrete** tries to fuse some operations into table lookups automatically, so you don't need to create the lookup tables manually: ```python -import concrete.numpy as cnp +from concrete import fhe import numpy as np -@cnp.compiler({"x": "encrypted"}) +@fhe.compiler({"x": "encrypted"}) def f(x): return (42 * np.sin(x)).astype(np.int64) // 10 @@ -162,14 +158,14 @@ for x in range(8): ``` {% hint style="info" %} -All lookup tables need to be from integers to integers. So, without `.astype(np.int64)`, **Concrete-Numpy** will not be able to fuse. +All lookup tables need to be from integers to integers. So, without `.astype(np.int64)`, **Concrete** will not be able to fuse. {% endhint %} The function is first traced into: ![](../\_static/tutorials/table-lookup/1.initial.graph.png) -Then, **Concrete-Numpy** fuses appropriate nodes: +Then, **Concrete** fuses appropriate nodes: ![](../\_static/tutorials/table-lookup/3.final.graph.png) diff --git a/frontends/concrete-python/docs/tutorial/tagging.md b/docs/tutorial/tagging.md similarity index 95% rename from frontends/concrete-python/docs/tutorial/tagging.md rename to docs/tutorial/tagging.md index 280893356..fca3a2423 100644 --- a/frontends/concrete-python/docs/tutorial/tagging.md +++ b/docs/tutorial/tagging.md @@ -1,19 +1,19 @@ # Tagging -When you have big circuits, keeping track of which node corresponds to which part of your code becomes very hard. Tagging system could simplify such situations: +When you have big circuits, keeping track of which node corresponds to which part of your code becomes very hard. Tagging system could simplify such situations: ```python def g(z): - with cnp.tag("def"): + with fhe.tag("def"): a = 120 - z b = a // 4 return b def f(x): - with cnp.tag("abc"): + with fhe.tag("abc"): x = x * 2 - with cnp.tag("foo"): + with fhe.tag("foo"): y = x + 42 z = np.sqrt(y).astype(np.int64) diff --git a/frontends/concrete-python/README.md b/frontends/concrete-python/README.md index ce92b02a0..f27925c7b 100644 --- a/frontends/concrete-python/README.md +++ b/frontends/concrete-python/README.md @@ -1,152 +1,18 @@ -

- - -

+# Python Frontend -

- - - - - - - - - - - - - - - - - - - - -

- - -**Concrete Numpy** is an open-source library which simplifies the use of fully homomorphic encryption (FHE) in Python. - -FHE is a powerful cryptographic tool, which allows computation to be performed directly on encrypted data without needing to decrypt it first. - -With FHE, you can build services that preserve the privacy of the users. FHE is also great against data breaches as everything is done on encrypted data. Even if the server is compromised, in the end no sensitive data is leaked. - -## Main features - -- Ability to compile Python functions (that may use NumPy within) to their FHE equivalents, to operate on encrypted data -- Support for [large collection of operators](https://docs.zama.ai/concrete-numpy/getting-started/compatibility) -- Partial support for floating points -- Support for table lookups on integers -- Support for integration with Client / Server architectures - -## Installation - -| OS / HW | Available on Docker | Available on PyPI | -|:------------------------------------:|:-------------------:|:-----------------:| -| Linux | Yes | Yes | -| Windows | Yes | Coming soon | -| Windows Subsystem for Linux | Yes | Yes | -| macOS (Intel) | Yes | Yes | -| macOS (Apple Silicon, ie M1, M2 etc) | Yes (Rosetta) | Coming soon | - - -The preferred way to install Concrete Numpy is through PyPI: - -```shell -pip install concrete-numpy -``` - -You can get the concrete-numpy docker image by pulling the latest docker image: - -```shell -docker pull zamafhe/concrete-numpy:v0.10.0 -``` - -You can find more detailed installation instructions in [installing.md](docs/getting-started/installing.md) - -## Getting started - -```python -import concrete.numpy as cnp - -def add(x, y): - return x + y - -compiler = cnp.Compiler(add, {"x": "encrypted", "y": "encrypted"}) -inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, 5), (5, 4)] - -print(f"Compiling...") -circuit = compiler.compile(inputset) - -print(f"Generating keys...") -circuit.keygen() - -examples = [(3, 4), (1, 2), (7, 7), (0, 0)] -for example in examples: - encrypted_example = circuit.encrypt(*example) - encrypted_result = circuit.run(encrypted_example) - result = circuit.decrypt(encrypted_result) - print(f"Evaluation of {' + '.join(map(str, example))} homomorphically = {result}") -``` - -or if you have a simple function that you can decorate, and you don't care about explicit steps of key generation, encryption, evaluation and decryption: - -```python -import concrete.numpy as cnp - -@cnp.compiler({"x": "encrypted", "y": "encrypted"}) -def add(x, y): - return x + y - -inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 1), (3, 2), (6, 1), (1, 7), (4, 5), (5, 4)] - -print(f"Compiling...") -circuit = add.compile(inputset) - -examples = [(3, 4), (1, 2), (7, 7), (0, 0)] -for example in examples: - result = circuit.encrypt_run_decrypt(*example) - print(f"Evaluation of {' + '.join(map(str, example))} homomorphically = {result}") -``` - -## Documentation - -Full, comprehensive documentation is available at [https://docs.zama.ai/concrete-numpy](https://docs.zama.ai/concrete-numpy). - -## Target users - -Concrete Numpy is a generic library that supports a variety of use cases. Because of this flexibility, -it doesn't provide primitives for specific use cases. - -If you have a specific use case, or a specific field of computation, you may want to build abstractions on top of Concrete Numpy. - -One such example is [Concrete ML](https://github.com/zama-ai/concrete-ml), which is built on top of Concrete Numpy to simplify Machine Learning oriented use cases. - -## Tutorials - -Various tutorials are proposed in the documentation to help you start writing homomorphic programs: - -- How to use Concrete Numpy with [Decorators](https://docs.zama.ai/concrete-numpy/tutorials/decorator) -- Partial support of [Floating Points](https://docs.zama.ai/concrete-numpy/tutorials/floating_points) -- How to perform [Table Lookup](https://docs.zama.ai/concrete-numpy/tutorials/table_lookup) - -More generally, if you have built awesome projects using Concrete Numpy, feel free to let us know, and we'll link to it! - -## Setting up for local development +## Setup for development ```shell # clone the repository -git clone https://github.com/zama-ai/concrete-open-source.git -cd concrete-open-source +git clone https://github.com/zama-ai/concrete.git +cd concrete # create virtual environment cd frontends/concrete-python make venv # activate virtual environment -source .vevn/bin/activate +source .venv/bin/activate # build the compiler bindings cd ../../compilers/concrete-compiler/compiler @@ -160,17 +26,3 @@ echo "export COMPILER_BUILD_DIRECTORY=$(pwd)/build" >> ~/.bashrc cd ../../../frontends/concrete-python make pytest ``` - -Building python bindings requires some python packages to be installed, hence virtual environment is created and activated before building compiler bindings. - -Also, you don't have to follow these steps exactly. As long as the compiler is built with CMake in release mode and build directory is exported as the environment variable `COMPILER_BUILD_DIRECTORY`, it'll be okay. - -## Need support? - - - - - -## License - -This software is distributed under the BSD-3-Clause-Clear license. If you have any questions, please contact us at hello@zama.ai. diff --git a/frontends/concrete-python/concrete/fhe/compilation/utils.py b/frontends/concrete-python/concrete/fhe/compilation/utils.py index fdd8d238b..968df8101 100644 --- a/frontends/concrete-python/concrete/fhe/compilation/utils.py +++ b/frontends/concrete-python/concrete/fhe/compilation/utils.py @@ -368,7 +368,7 @@ def is_single_common_ancestor( # - [...] = Node of which single common ancestor is searched # - {[...]} = Both Candidate Node and Node of which single common ancestor is searched # - # Consider the folowing graph: + # Consider the following graph: # # (3) (x) (2) # \ / \ / @@ -393,7 +393,7 @@ def is_single_common_ancestor( # which means there is path leading to the addition node and that path doesn't include # the multiplication node, so we conclude multiplication node is not a single common ancestor # - # Now, consider the folowing graph: + # Now, consider the following graph: # # (3) {x} (2) # \ / \ / @@ -419,7 +419,7 @@ def is_single_common_ancestor( # In this subgraph, every node except the candidate node # will keep all of their non-constant predecessors, # which means all of their non-constant predecessors originated - # from the `candidate`, so it's a single common anscestor. + # from the `candidate`, so it's a single common ancestor. # # When you think about it, this implementation makes a lot of sense for our purposes # It basically determines if `nodes` "solely" depend on the `candidate`, @@ -532,7 +532,7 @@ def convert_subgraph_to_subgraph_node( Args: graph (Graph): - orginal graph + original graph all_nodes (Dict[Node, None]): all nodes in the subgraph diff --git a/frontends/concrete-python/docs/README.md b/frontends/concrete-python/docs/README.md deleted file mode 100644 index ad583be34..000000000 --- a/frontends/concrete-python/docs/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# What is Concrete Numpy? - -[⭐️ Star the repo on Github](https://github.com/zama-ai/concrete-numpy) | 🗣 [Community support forum](https://community.zama.ai/c/concrete-numpy) | 📁 [Contribute to the project](dev/contributing.md) - -
- -**Concrete-Numpy** is an open-source library which simplifies the use of fully homomorphic encryption (FHE). - -FHE is a powerful cryptographic tool, which allows computation to be performed directly on encrypted data without needing to decrypt it first. With FHE, you can build services that preserve privacy for all users. FHE is also great against data breaches as everything is done on encrypted data. Even if the server is compromised, in the end no sensitive data is leaked. - -## Organization of this documentation - -This documentation is split into several sections: - -* **Getting Started** gives you the basics, -* **Tutorials** gives you some essential examples on various features of the library, -* **How to** helps you perform specific tasks, -* and **Developer** explains the inner workings of the library and everything related to contributing to the project. - -## Looking for support? Ask our team! - -* Support forum: [https://community.zama.ai](https://community.zama.ai) (we answer in less than 24 hours). -* Live discussion on the FHE.org discord server: [https://discord.fhe.org](https://discord.fhe.org) (inside the #**concrete** channel). -* Do you have a question about Zama? You can write us on [Twitter](https://twitter.com/zama\_fhe) or send us an email at: **hello@zama.ai** diff --git a/frontends/concrete-python/docs/_static/tutorials/artifacts/auto/1.initial.graph.png b/frontends/concrete-python/docs/_static/tutorials/artifacts/auto/1.initial.graph.png deleted file mode 100644 index 462f2093c3a7bcebb1363bc0fed6d85e3e85f06a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8607 zcmb_?Ra6{Z(Cy&v!EJCd!QI{6U4pv=cXxM!1rNjEZb5=;fB+%5y9Ian=lj>a&-dl7 zUe(nPN2=>opIy89#Hy*tVxW?s0ssIEc{wQ!sJ4YlFES$Zj?0k4167FTin3CG_y4Y< z?uv8(00@wm64&y{KP&Lg*IIad-Y$YMt}?|W~6&bqbxyW zBbjvpHUM$B?Mu{qV;XQJrO>4@ihzuNu`6L=CkO~yvzH3|F7A^#IlZlIT7R9MG6@zg zI+*z1XSsh9Eaad5sLBu0&$2R)F#xX^h7gg+CKNILC(*6l2)3A(6=(-zu#VA5JA7`q zHb3?AZ4|!X6YN015|By+eHlnKj95WF0EB-W;luS&-nP@KXi7nHMHugOsC&lrH=1!B zMN#bAMg@oj2_>x@^W>Zo{Jia7Z5oj5bdfyjC98L$cH~KfXd1Z&ao{ug^>M1)XObT=Fprb&~0sQS<`|0<#ecH8KUZuwsx_pdzkDCW5X! ze=TSE6o}P%H}k7AS*+a)GMC*)GygWVnI8Bt4$qaI;w#D%@T(6);{dU1{PKrrGuL4B zSHIF;DKNvCukmadeH$30t55e!v!a1gAnA1^{qG&+(A^Xat)g*XH>iMM4ueLn^Mqhq z1`{?DvQS3^T8;!RZIxM1F=V{&DU*#{zp_FWi0V$GkD_phqA>>9HqEsRlvhT#Jj|Zo z*#5Bgj9krPR&P+i%U^ZLE4h$6@kH)x0Qp!GgE^7w7urEv9>)#J?^i7?^VN@os<$La_Y6Cg(udEtNik$jDk-O~ z8m$3z_`!ilMiPPG8v)#k^_a(=BU^vV7OPvTfgD|_N7MB(zgzkXG0F0U6pmofKGH#R z$FhTFSpK68-}Q;8`Kx{5z0qpSCpps|>{n^w705DA=#G>KUGF5 z$APy?lix}L@I?2SPx$p-ZciHko|3m@GL`EeWOq_G9#m`cLL0&o*$HG-w&yTj_ru-U zd~?z;&BL}_df>MSdX=@T!U$$+}&U0DYpZNbNK>uaxu_$MPVwj;57U{4y7Li3t!_bUc1ea?<);(YE}D7 zWIg?DYA_aWsnv;eZ*Na2mkT9C@Ztwv)q(AKe=x3O&j6id|TT>lcha9z;WZE#%T_-`r&h377%$EUyYEr0%G&mAMBXC^J~ z@tCv_fV@w7%md+Qc09iFdP5n?H|y53rT0`%2C| zkJj|cxr2WjEPS7iDwaAuKcNw_IP&I*`5=V4rp(@+E+4xYD5s3uifx#-Q|R|DUEKbS z{qW8IoF5U3VltQ8;o)XZmH*2&d}e0mkN3CdLk|HHpDlzaEXrSbE-ot-mF}SB6*Sz}*5%N4W?+<8*Z3qjc>iLN(OfL+187%;;;J))QRTn7BS<$gzIpZYPt@WjZ8Z}Opw8I-h4MFfSL1mW6Oa(jf)PuG94^ebw{ExH zN2h-GccPeJaZ9~(*Tn=+a{Q%|Dw~i)9ECUes&+_UWLwplkZSN zi8l$oV{#@CR}1v}jceni)aa#eZe4o*7rd-9)ezbnI`YO@^T-97;s+_ce3=B@yMZ77 zSO8_?Br2+beJ3O<#G9b1GTY^Fxdj5iWN%*Nmzi?2kAjZp-}WQDad?H00MA=^{j7o! z+~6eGF%8+-W~7F9AKZ|3huXn_jfDD4N|9ir#9S5^mVudGEMWctnoIYh1Fk6H7N~0X z#tE$<$Q=L(+(0{Qyqc}=i?aB8M^>^q?8}$5AJvo#4uPWCht+?i zE@HX0x>%hxzJFYB_{osFWV>1w1=e_b4imq+lT9n7xA9dTS?0L1`uW3+g^Wt|R zV(Pfje?**O!35Hr7?Nt=X6CZzk^Jezmv+Qy*&hy^Pmsq1V^Ps7Y;ODx?k|m z-42We_{!()>DjJe%jtjL9$Lr{zJ%}wsFAx2{;;JVdv|e@i;qc-FtRD%-V0X0JSANZ zO;)I*xlJ`ilO5tg2PMg2H#kjG{bG6Gyn`G0aln;RS+>fVxSP`^#jNgDkU74%sD9Zm z*dB*ZQ`BSX!ts6uj0(+e?m)+hzsf3LftdIgHZth?9iRc3no!yj=zY&EZ?dI=_V|gQ zI9=)IFTCL5^6$R;U-O%e!=iW8n+zy=m%(CA?P2#l5@BEjGShD2~8wpNlDk-dGarR7w0ijkqUdLYN z;t+6>T=#K?)OOUt=Ug^i=!y-9ETJQ)OQ%rMqC6Mx%m;Q5u6QFgP>O`U%CR&~t#8ug zok?gXEmUy(B##%#2CJ*y1hV#}%w@Nm!3}Lnkr${R&MK<0wbPO@pt%wd>{a_e#+1-V>YwAg8ALPDsMtiPl7#P{y_& zh#@vS*Bf7^t{Xg@58|H|V;Vj4tjKz-#}s@YNmhlE*gHh@U4l7C2t)aS^<>3OW> zb+$YN1)g;|lvLRYYTKRRL;yOah|uP8437DG$L-0Ytk(DMGnL3!mJqD0-HVs&X{68Z zZ!;W2(WC`&Mcd{$&6)XRM9kS4v}wCp85!_K4yqoYFfzBU;frs!;!qR*)|-j_3k^9~ohja0 z1M_G>hZ|0&R5dUlp$sBwm)wb_42l`E+$QXOkQS8t!zO?)PM;oI@y#!;+yDM*)qUD` zx)%yjj%%Hn<%-#9sj0I`xQHcl%(qYwLCc#O-X4ngJu1(hIr7LC@=ddv$olgBdjG$E z)Kgzq-n?5GBFKSan@RfpvLg>Bg-{Hw{LR@)_QS*BDzIU$1&D=?2*=OQf5t46eyA0w zCM)%Sn9BcUEdNg(&CUDcVLM*vW=2vjtr4#AKwC>B<R5pT%rA{KNN}n#F=|#tdbA zVxrV$`WqKrk3u;$FK_ng>1M2LDLJ{$kd=)Mr^lh%eBy4GPSpZBxj^$k8XWmoUS4{st;R3<)J z8~I$*b`GL4B^>2Q{?@zqb{o>hG z^dt;^L_Uos>D4Vbbw&^#$_Aeyg5bPt$cO_e${+^KkU@BwA=zw;nT6P_eI_k~Z!}nC za8XSWRfY?IF|Blikt=YcqFI%W{;0) zocYRxkx@jEmYv-VO{GGBD3JBY-xYnWi|=Xl2)My8@^e%{v=~WGbZCF?;*&X5!5?jk z`Ld41AQEXt9>fNiAjYTu1cMqFPh9YhSRV6yF^eG?DJxu{s9GLLR>vJDIDi!LP7cOR zPhRBFTqb%O+Z#ng&}&gs>{pp< zT8}td)&?0_zBE2m{eCoU3&JS>BvsX4p3j>YJ&FIhz4=JMAm$$~tzhx#N5)5*Q65$N z6dzJc5tvT2*NeI}#7q~lDFgNcln{~|!Z0%c5euO^VW7*57gAz}Rb$8aPkq2$skw^P z3d6qMT_N%z77SNq3Lj3Ijl?SQyThG@+Dl3v<9!nduIwG>_c>C3TcXDUvfB%Mg^hTP zDhPi^dpjHdopUeW5x=yp@c{0b78`yr86U(DltCoaOlLHt_FQRL?u;S=;o1**G?_gB zCye`^=(^qoy?ZB-!Wx@m)v_3d{=?R4A&J{(w3jM?&ry{eC;L%KzJ$2PDt^S_T5ua| zvSB#MpLUL2QzmTo3l0RUUFEYj})6e$ja%gcOq@8IDhtmxqCmbxJP)V zfOTH~%Hu~VpKR?zszGbJi-!0zT*@VUal(y(YKmoOzu>An2>`=Vh$Z5xnPf$r@d4v!>>#8_rI_s5i6hj-0)HKjxlew!QJ<>NDuNpXz+ zaWce2DkbW^UNL^`vWCgnZkz&d{)O{;I)x)!jyX{ZlS8Wq#fC7XN-6)hSNQn_$^uf! zv@ka+*|}EUclH?z&CM4GPIE$0$%fd_#J1kXh;mXFWu-n6f;ZzehX~bK8Syd9?FIjC{v|-@2{U!#5$)&RWNy$0?mCD^^Be+I#*&>!w+BhUr7x!r>rarAZqxCQsUF z+>tv;HP?6|K7fa>`lOS9phgg!{<)NLBOI!;=H%(eUR<;Wpb|s5Dwn>|PB{EC6(75p zR+)Ub36fYI-P<%d>K~V(z{>c+Ttjr!U#m!a)A1HNVuu}u=)inw*OEe_$I6=-2baZG*J`|07oItuFo(3QTeaHsNd`lG$+Jt#;i#-8=q>VSEL`=C%lS_NyG=3M}v@) z?vZHOZo*AO0rqAC)7=Wy%67kt7K5zZ2*O44BV9{+**w7>u5XL|9$`#e=}weIp=g+l zc&~o8?FgAdq29tD11sGeF3qjB*iIse_!GrflmldeTP&AwMg zZ!&}T1FfWiR<&-1W2NK5#L3YY2){hbShbTBvpcZn&9#vFWAtCeXJo_iv~E@R8g29r znXunrf%ziabtuxi_2wf<!2 z)f33UEGNG9V?TWYdtYa>dOETHW~#MZ?3_COr|IWGLC4vqrt zX6jB!OdTyf^dR4+pTyhK2i_SmUxlGC;0i@HnPSMgiT!gQU^szzClTCaP$TqM#vxT8 z5-0%8`!M}P*x6G(PyVQDYfD2bDmiRs5~Y_lPGRj-pO6VuklXYIbhGI6Vr}$#?V0-X%&Y7E<>m3(O6(1qgs* z#Q5uVo?$Z;SjyKHT~T-NUF$oU19eko`NWW_50ha zQSj?6Itf?INo`ls)<85Tw2*e=7dVITP!vRs)}$Xm#myZ$u*?&=d?0%PQA-l0`YH}P z0c)6I!+3b&cz!ZR$2))`j6OO!X?eXrMJ5vPRlmvl%Vr-8z3MlmWD4QG(6@~rM{V8F z>FQgo__f$I;%{Rzsd-5M>oUN20fuv%#BH62@gUe4UPx)$J23DH!aUWz{PsEexs#)-q<=&sK*_g!Jm4D zL}}VD4wDSO91dBO_(}U^bq~L-1LolfmOb_NUC4SzKAgTKH9AUC0Yf!xC)$=o8;!+~ zqS~$s&tHoI*VcRS&9+n0Z-=DmIj*G-CzDtS3kk(`dabB#edKiKGBwGwoN{QWv~tg*W>2F>S=+vc-lQUkoE#BZ5PnU*xZn5C4v1aDFq1&8c7nKkt*H#IZF|V{UG8V zQ6227^!fO@wm>UUZq!bOIsC%CcC*%0@CQ=0-x)>8hzz6m`wEo%nuKw^jra=Y^cU8p zH|kcvlukK*)7z|Pv4zj=mIKbZ9g@-%lQU<~9eMcl~^TtTZ3j^OHP+32VQ6G{ZWv-^yr2ge(p)7`< z4pjUlZoh;t@(n9dnvzFkMJXQ{#d)Iq)*&|z4?d7V`ldY;#2 zDd}To<^&huf%UN}WIlu&Wp?G0MZwEu4kG^dq%8a zB2?0@r5yW!v%xGjq4{$@@Y95>My3MV_p!#ZcCN7n%BKqPM|P7e#cvt-)YAxZjYe;c za-lnUm=*Sk)66{jEMK=JRdSgY&+NV^*C>9se5JS=2GvS_p^^HHsv1-F%JxC!`ktG| z1R-Yv*b_NsQi_o^MV(Vv=Q+=Z+}T|tHP)dZ{jXlO#%?m@b)#rM;`_{#qwXJJbFobj z!TX7ycrsQ-kb;-Q5~n%!32{e=UgW3`mpKK*OmfYc(N_w4H&nnR!E&lsJImG4Upjbq z6#w0!3HXe+=WjC4 z+;I;!q_~G$XGOAFolaRj|8|A+kBcOxl>{(Sg@18_$^c!YRFo=;ddwhA`2qU8ia zVABRkX4_-REI#G;4rwqfsKgsWUk*qPKDL^$zKpM4lIvqL+K`>Z*&c}@__Ivw!yKvg ziNkZj8Hbr3=u&C$wNmrq`a;sGYIIcZ32g48ITRZkcpMl(Gob6!^d^whHS!`-BbAMD zl-!}bF9N%gEIza$b>*rmy3dd!{-Ur`tJC;)%!+ADKCZ$Z)9?xu@iay4%4V>LW97=} z7jo)Zk-)W${H_u&vjdk)+Trl?|B$BkjQk zXDZW1IBF%-HR8Ky3to6sq|1)pUXN1Z`6DAs+EnA2kfFh)9IT{(;#x9>@bsGdtS6;LRDG=LvehDr=ABKYI2Vkxx$1VXSoHn1`V+F2D7`Cf!w!G314$3TXE{9 zkgxi@)X-I{7Pl4;z{)AEpJ$!(a zDUyI!K5`uBb~FFTd*N8Diu_2wqh1)%=oCJB7Gy38I+fRcM^>7v8~ZSzGv`@?=d7!x zv;_db$o+Q~Kt;#5QYVE@e^9pd(-!HmlhQP=`X%Hun~T^$O)KBF3Qc#~2P1Dv=;^k9HuMs{V=hwq_UpanDZ|RYWZG z?09jNtJ4^Sdf%BILD!`_i9JKLSJkcR4ea?b^WPO+ecf=2zUSoaopGiuAQN;T*ZC%g zZn>*_nuGL-+cz&4yYz$g$dmR%=s%BG#cYgN%|XW6%qqZ^*t1LOe&|j+5t$wj8vfio zkM&lRfQe;aGUcb%Ja!XtE=y1nMOXlpV1)1A&XI1kU5d-zk#$_q{MflM&^?3sFZ!!t z1`EGNj7k_uSXIAp#TfqaxHh%*zchbNajei|+Ej4`a)y1mT#sU0;XFK<%hvqc*#_j} uh!})NDSmT!Y5wNE-etoWB9h^Em=v|RTUClEI_QZDfV{MdRISA4u>S#hRa&-dl7 zUe(nPN2=>opIy89#Hy*tVxW?s0ssIEc{wQ!sJ4YlFES$Zj?0k4167FTin3CG_y4Y< z?uv8(00@wm64&y{KP&Lg*IIad-Y$YMt}?|W~6&bqbxyW zBbjvpHUM$B?Mu{qV;XQJrO>4@ihzuNu`6L=CkO~yvzH3|F7A^#IlZlIT7R9MG6@zg zI+*z1XSsh9Eaad5sLBu0&$2R)F#xX^h7gg+CKNILC(*6l2)3A(6=(-zu#VA5JA7`q zHb3?AZ4|!X6YN015|By+eHlnKj95WF0EB-W;luS&-nP@KXi7nHMHugOsC&lrH=1!B zMN#bAMg@oj2_>x@^W>Zo{Jia7Z5oj5bdfyjC98L$cH~KfXd1Z&ao{ug^>M1)XObT=Fprb&~0sQS<`|0<#ecH8KUZuwsx_pdzkDCW5X! ze=TSE6o}P%H}k7AS*+a)GMC*)GygWVnI8Bt4$qaI;w#D%@T(6);{dU1{PKrrGuL4B zSHIF;DKNvCukmadeH$30t55e!v!a1gAnA1^{qG&+(A^Xat)g*XH>iMM4ueLn^Mqhq z1`{?DvQS3^T8;!RZIxM1F=V{&DU*#{zp_FWi0V$GkD_phqA>>9HqEsRlvhT#Jj|Zo z*#5Bgj9krPR&P+i%U^ZLE4h$6@kH)x0Qp!GgE^7w7urEv9>)#J?^i7?^VN@os<$La_Y6Cg(udEtNik$jDk-O~ z8m$3z_`!ilMiPPG8v)#k^_a(=BU^vV7OPvTfgD|_N7MB(zgzkXG0F0U6pmofKGH#R z$FhTFSpK68-}Q;8`Kx{5z0qpSCpps|>{n^w705DA=#G>KUGF5 z$APy?lix}L@I?2SPx$p-ZciHko|3m@GL`EeWOq_G9#m`cLL0&o*$HG-w&yTj_ru-U zd~?z;&BL}_df>MSdX=@T!U$$+}&U0DYpZNbNK>uaxu_$MPVwj;57U{4y7Li3t!_bUc1ea?<);(YE}D7 zWIg?DYA_aWsnv;eZ*Na2mkT9C@Ztwv)q(AKe=x3O&j6id|TT>lcha9z;WZE#%T_-`r&h377%$EUyYEr0%G&mAMBXC^J~ z@tCv_fV@w7%md+Qc09iFdP5n?H|y53rT0`%2C| zkJj|cxr2WjEPS7iDwaAuKcNw_IP&I*`5=V4rp(@+E+4xYD5s3uifx#-Q|R|DUEKbS z{qW8IoF5U3VltQ8;o)XZmH*2&d}e0mkN3CdLk|HHpDlzaEXrSbE-ot-mF}SB6*Sz}*5%N4W?+<8*Z3qjc>iLN(OfL+187%;;;J))QRTn7BS<$gzIpZYPt@WjZ8Z}Opw8I-h4MFfSL1mW6Oa(jf)PuG94^ebw{ExH zN2h-GccPeJaZ9~(*Tn=+a{Q%|Dw~i)9ECUes&+_UWLwplkZSN zi8l$oV{#@CR}1v}jceni)aa#eZe4o*7rd-9)ezbnI`YO@^T-97;s+_ce3=B@yMZ77 zSO8_?Br2+beJ3O<#G9b1GTY^Fxdj5iWN%*Nmzi?2kAjZp-}WQDad?H00MA=^{j7o! z+~6eGF%8+-W~7F9AKZ|3huXn_jfDD4N|9ir#9S5^mVudGEMWctnoIYh1Fk6H7N~0X z#tE$<$Q=L(+(0{Qyqc}=i?aB8M^>^q?8}$5AJvo#4uPWCht+?i zE@HX0x>%hxzJFYB_{osFWV>1w1=e_b4imq+lT9n7xA9dTS?0L1`uW3+g^Wt|R zV(Pfje?**O!35Hr7?Nt=X6CZzk^Jezmv+Qy*&hy^Pmsq1V^Ps7Y;ODx?k|m z-42We_{!()>DjJe%jtjL9$Lr{zJ%}wsFAx2{;;JVdv|e@i;qc-FtRD%-V0X0JSANZ zO;)I*xlJ`ilO5tg2PMg2H#kjG{bG6Gyn`G0aln;RS+>fVxSP`^#jNgDkU74%sD9Zm z*dB*ZQ`BSX!ts6uj0(+e?m)+hzsf3LftdIgHZth?9iRc3no!yj=zY&EZ?dI=_V|gQ zI9=)IFTCL5^6$R;U-O%e!=iW8n+zy=m%(CA?P2#l5@BEjGShD2~8wpNlDk-dGarR7w0ijkqUdLYN z;t+6>T=#K?)OOUt=Ug^i=!y-9ETJQ)OQ%rMqC6Mx%m;Q5u6QFgP>O`U%CR&~t#8ug zok?gXEmUy(B##%#2CJ*y1hV#}%w@Nm!3}Lnkr${R&MK<0wbPO@pt%wd>{a_e#+1-V>YwAg8ALPDsMtiPl7#P{y_& zh#@vS*Bf7^t{Xg@58|H|V;Vj4tjKz-#}s@YNmhlE*gHh@U4l7C2t)aS^<>3OW> zb+$YN1)g;|lvLRYYTKRRL;yOah|uP8437DG$L-0Ytk(DMGnL3!mJqD0-HVs&X{68Z zZ!;W2(WC`&Mcd{$&6)XRM9kS4v}wCp85!_K4yqoYFfzBU;frs!;!qR*)|-j_3k^9~ohja0 z1M_G>hZ|0&R5dUlp$sBwm)wb_42l`E+$QXOkQS8t!zO?)PM;oI@y#!;+yDM*)qUD` zx)%yjj%%Hn<%-#9sj0I`xQHcl%(qYwLCc#O-X4ngJu1(hIr7LC@=ddv$olgBdjG$E z)Kgzq-n?5GBFKSan@RfpvLg>Bg-{Hw{LR@)_QS*BDzIU$1&D=?2*=OQf5t46eyA0w zCM)%Sn9BcUEdNg(&CUDcVLM*vW=2vjtr4#AKwC>B<R5pT%rA{KNN}n#F=|#tdbA zVxrV$`WqKrk3u;$FK_ng>1M2LDLJ{$kd=)Mr^lh%eBy4GPSpZBxj^$k8XWmoUS4{st;R3<)J z8~I$*b`GL4B^>2Q{?@zqb{o>hG z^dt;^L_Uos>D4Vbbw&^#$_Aeyg5bPt$cO_e${+^KkU@BwA=zw;nT6P_eI_k~Z!}nC za8XSWRfY?IF|Blikt=YcqFI%W{;0) zocYRxkx@jEmYv-VO{GGBD3JBY-xYnWi|=Xl2)My8@^e%{v=~WGbZCF?;*&X5!5?jk z`Ld41AQEXt9>fNiAjYTu1cMqFPh9YhSRV6yF^eG?DJxu{s9GLLR>vJDIDi!LP7cOR zPhRBFTqb%O+Z#ng&}&gs>{pp< zT8}td)&?0_zBE2m{eCoU3&JS>BvsX4p3j>YJ&FIhz4=JMAm$$~tzhx#N5)5*Q65$N z6dzJc5tvT2*NeI}#7q~lDFgNcln{~|!Z0%c5euO^VW7*57gAz}Rb$8aPkq2$skw^P z3d6qMT_N%z77SNq3Lj3Ijl?SQyThG@+Dl3v<9!nduIwG>_c>C3TcXDUvfB%Mg^hTP zDhPi^dpjHdopUeW5x=yp@c{0b78`yr86U(DltCoaOlLHt_FQRL?u;S=;o1**G?_gB zCye`^=(^qoy?ZB-!Wx@m)v_3d{=?R4A&J{(w3jM?&ry{eC;L%KzJ$2PDt^S_T5ua| zvSB#MpLUL2QzmTo3l0RUUFEYj})6e$ja%gcOq@8IDhtmxqCmbxJP)V zfOTH~%Hu~VpKR?zszGbJi-!0zT*@VUal(y(YKmoOzu>An2>`=Vh$Z5xnPf$r@d4v!>>#8_rI_s5i6hj-0)HKjxlew!QJ<>NDuNpXz+ zaWce2DkbW^UNL^`vWCgnZkz&d{)O{;I)x)!jyX{ZlS8Wq#fC7XN-6)hSNQn_$^uf! zv@ka+*|}EUclH?z&CM4GPIE$0$%fd_#J1kXh;mXFWu-n6f;ZzehX~bK8Syd9?FIjC{v|-@2{U!#5$)&RWNy$0?mCD^^Be+I#*&>!w+BhUr7x!r>rarAZqxCQsUF z+>tv;HP?6|K7fa>`lOS9phgg!{<)NLBOI!;=H%(eUR<;Wpb|s5Dwn>|PB{EC6(75p zR+)Ub36fYI-P<%d>K~V(z{>c+Ttjr!U#m!a)A1HNVuu}u=)inw*OEe_$I6=-2baZG*J`|07oItuFo(3QTeaHsNd`lG$+Jt#;i#-8=q>VSEL`=C%lS_NyG=3M}v@) z?vZHOZo*AO0rqAC)7=Wy%67kt7K5zZ2*O44BV9{+**w7>u5XL|9$`#e=}weIp=g+l zc&~o8?FgAdq29tD11sGeF3qjB*iIse_!GrflmldeTP&AwMg zZ!&}T1FfWiR<&-1W2NK5#L3YY2){hbShbTBvpcZn&9#vFWAtCeXJo_iv~E@R8g29r znXunrf%ziabtuxi_2wf<!2 z)f33UEGNG9V?TWYdtYa>dOETHW~#MZ?3_COr|IWGLC4vqrt zX6jB!OdTyf^dR4+pTyhK2i_SmUxlGC;0i@HnPSMgiT!gQU^szzClTCaP$TqM#vxT8 z5-0%8`!M}P*x6G(PyVQDYfD2bDmiRs5~Y_lPGRj-pO6VuklXYIbhGI6Vr}$#?V0-X%&Y7E<>m3(O6(1qgs* z#Q5uVo?$Z;SjyKHT~T-NUF$oU19eko`NWW_50ha zQSj?6Itf?INo`ls)<85Tw2*e=7dVITP!vRs)}$Xm#myZ$u*?&=d?0%PQA-l0`YH}P z0c)6I!+3b&cz!ZR$2))`j6OO!X?eXrMJ5vPRlmvl%Vr-8z3MlmWD4QG(6@~rM{V8F z>FQgo__f$I;%{Rzsd-5M>oUN20fuv%#BH62@gUe4UPx)$J23DH!aUWz{PsEexs#)-q<=&sK*_g!Jm4D zL}}VD4wDSO91dBO_(}U^bq~L-1LolfmOb_NUC4SzKAgTKH9AUC0Yf!xC)$=o8;!+~ zqS~$s&tHoI*VcRS&9+n0Z-=DmIj*G-CzDtS3kk(`dabB#edKiKGBwGwoN{QWv~tg*W>2F>S=+vc-lQUkoE#BZ5PnU*xZn5C4v1aDFq1&8c7nKkt*H#IZF|V{UG8V zQ6227^!fO@wm>UUZq!bOIsC%CcC*%0@CQ=0-x)>8hzz6m`wEo%nuKw^jra=Y^cU8p zH|kcvlukK*)7z|Pv4zj=mIKbZ9g@-%lQU<~9eMcl~^TtTZ3j^OHP+32VQ6G{ZWv-^yr2ge(p)7`< z4pjUlZoh;t@(n9dnvzFkMJXQ{#d)Iq)*&|z4?d7V`ldY;#2 zDd}To<^&huf%UN}WIlu&Wp?G0MZwEu4kG^dq%8a zB2?0@r5yW!v%xGjq4{$@@Y95>My3MV_p!#ZcCN7n%BKqPM|P7e#cvt-)YAxZjYe;c za-lnUm=*Sk)66{jEMK=JRdSgY&+NV^*C>9se5JS=2GvS_p^^HHsv1-F%JxC!`ktG| z1R-Yv*b_NsQi_o^MV(Vv=Q+=Z+}T|tHP)dZ{jXlO#%?m@b)#rM;`_{#qwXJJbFobj z!TX7ycrsQ-kb;-Q5~n%!32{e=UgW3`mpKK*OmfYc(N_w4H&nnR!E&lsJImG4Upjbq z6#w0!3HXe+=WjC4 z+;I;!q_~G$XGOAFolaRj|8|A+kBcOxl>{(Sg@18_$^c!YRFo=;ddwhA`2qU8ia zVABRkX4_-REI#G;4rwqfsKgsWUk*qPKDL^$zKpM4lIvqL+K`>Z*&c}@__Ivw!yKvg ziNkZj8Hbr3=u&C$wNmrq`a;sGYIIcZ32g48ITRZkcpMl(Gob6!^d^whHS!`-BbAMD zl-!}bF9N%gEIza$b>*rmy3dd!{-Ur`tJC;)%!+ADKCZ$Z)9?xu@iay4%4V>LW97=} z7jo)Zk-)W${H_u&vjdk)+Trl?|B$BkjQk zXDZW1IBF%-HR8Ky3to6sq|1)pUXN1Z`6DAs+EnA2kfFh)9IT{(;#x9>@bsGdtS6;LRDG=LvehDr=ABKYI2Vkxx$1VXSoHn1`V+F2D7`Cf!w!G314$3TXE{9 zkgxi@)X-I{7Pl4;z{)AEpJ$!(a zDUyI!K5`uBb~FFTd*N8Diu_2wqh1)%=oCJB7Gy38I+fRcM^>7v8~ZSzGv`@?=d7!x zv;_db$o+Q~Kt;#5QYVE@e^9pd(-!HmlhQP=`X%Hun~T^$O)KBF3Qc#~2P1Dv=;^k9HuMs{V=hwq_UpanDZ|RYWZG z?09jNtJ4^Sdf%BILD!`_i9JKLSJkcR4ea?b^WPO+ecf=2zUSoaopGiuAQN;T*ZC%g zZn>*_nuGL-+cz&4yYz$g$dmR%=s%BG#cYgN%|XW6%qqZ^*t1LOe&|j+5t$wj8vfio zkM&lRfQe;aGUcb%Ja!XtE=y1nMOXlpV1)1A&XI1kU5d-zk#$_q{MflM&^?3sFZ!!t z1`EGNj7k_uSXIAp#TfqaxHh%*zchbNajei|+Ej4`a)y1mT#sU0;XFK<%hvqc*#_j} uh!})NDSmT!Y5wNE-etoWB9h^Em=v|RTUClEI_QZDfV{MdRISA4u>S#hRWithin each iteration: - 2.1. We find a subgraph to fuse. - - 2.2. We search for a terminal node that is appropriate for fusing. - - 2.3. We crawl backwards to find the closest integer nodes to this node. - - 2.4. If there is a single node as such, we return the subgraph from this node to the terminal node. - - 2.5. Otherwise, we try to find the lowest common ancestor (lca) of this list of nodes. - - 2.6. If an lca doesn't exist, we say this particular terminal node is not fusable, and we go back to search for another subgraph. - - 2.7. Otherwise, we use this lca as the input of the subgraph and continue with `subgraph` node creation below. - - 2.8. We convert the subgraph into a `subgraph` node by checking fusability status of the nodes of the subgraph in this step. - - 2.10. We substitute the `subgraph` node to the original graph. - -## Limitations - -With the current implementation, we cannot fuse subgraphs that depend on multiple encrypted values where those values doesn't have a common lca (e.g., `np.round(np.sin(x) + np.cos(y))`). - -{% hint style="info" %} -[Kolmogorov–Arnold representation theorem](https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Arnold\_representation\_theorem) states that every multivariate continuous function can be represented as a superposition of continuous functions of one variable. Therefore, the case above could be handled in future versions of **Concrete-Numpy**. -{% endhint %} diff --git a/frontends/concrete-python/docs/dev/mlir.md b/frontends/concrete-python/docs/dev/mlir.md deleted file mode 100644 index 2dc6b4798..000000000 --- a/frontends/concrete-python/docs/dev/mlir.md +++ /dev/null @@ -1,17 +0,0 @@ -# MLIR - -The MLIR project is a sub-project of the LLVM project. It's designed to simplify building domain-specific compilers such as our **Concrete-Compiler**. - -**Concrete-Compiler** accepts MLIR as an input and emits compiled assembly code for a target architecture. - -**Concrete-Numpy** performs the MLIR generation from the computation graph. Code related to this conversion is in the `concrete/numpy/mlir` folder. - -The conversion can be performed using the `convert` method of the `GraphConverter` class. - -Within the `convert` method of `GraphConverter`: - -* MLIR compatibility of the graph is checked; -* bit width constraints are checked; -* negative lookup tables are offset; -* the computation graph is traversed and each node is converted to their corresponding MLIR representation using the `NodeConverter` class; -* and string representation of the resulting MLIR is returned. diff --git a/frontends/concrete-python/docs/dev/project_setup.md b/frontends/concrete-python/docs/dev/project_setup.md deleted file mode 100644 index 5c48ff53d..000000000 --- a/frontends/concrete-python/docs/dev/project_setup.md +++ /dev/null @@ -1,91 +0,0 @@ -# Project Setup - -{% hint style="info" %} -It is **strongly** recommended to use the development tool Docker. However, you are able to set the project up on a bare Linux or macOS as long as you have the required dependencies. You can see the required dependencies in `Dockerfile.dev` under `docker` directory. -{% endhint %} - -## Installing `Python` - -**Concrete-Numpy** is a `Python` library, so `Python` should be installed to develop it. `v3.8` and `v3.9` are, currently, the only supported versions. - -You probably have Python already, but in case you don't, or in case you have an unsupported version, you can google `how to install python 3.8` and follow one of the results. - -## Installing `Poetry` - -`Poetry` is our package manager. It drastically simplifies dependency and environment management. - -You can follow [this](https://python-poetry.org/docs/#installation) official guide to install it. - -## Installing `make` - -`make` is used to launch various commands such as formatting and testing. - -On Linux, you can install `make` using the package manager of your distribution. - -On macOS, you can install `gmake` via brew: - -```shell -brew install make -``` - -{% hint style="info" %} -In the following sections, be sure to use the proper `make` tool for your system (i.e., `make`, `gmake`, etc). -{% endhint %} - -## Cloning the repository - -Now, it's time to get the source code of **Concrete-Numpy**. - -Clone the git repository from GitHub using the protocol of your choice (ssh or https). - -## Setting up the environment - -Virtual environments are utilized to keep the project isolated from other `Python` projects in the system. - -To create a new virtual environment and install dependencies, use the command: - -```shell -make setup_env -``` - -## Activating the environment - -To activate the newly created environment, use: - -```shell -source .venv/bin/activate -``` - -## Syncing the environment - -From time to time, new dependencies will be added to the project and old ones will be removed.mThe command below will make sure the project has the proper environment, so run it regularly. - -```shell -make sync_env -``` - -## Troubleshooting - -### In native setups. - -If you are having issues in a native setup, you can try to re-create your environment like this: - -```shell -deactivate -rm -rf .venv -make setup_env -source .venv/bin/activate -``` - -If the problem persists, you should consider using Docker. If you are working on a platform specific feature and Docker is not an option, you should create an issue so that we can take a look at your problem. - -### In docker setups. - -If you are having issues in a docker setup, you can try to re-build the docker image: - -```shell -make docker_rebuild -make docker_start -``` - -If the problem persists, you should contact us for help. diff --git a/frontends/concrete-python/docs/dev/terminology_and_structure.md b/frontends/concrete-python/docs/dev/terminology_and_structure.md deleted file mode 100644 index 051810cff..000000000 --- a/frontends/concrete-python/docs/dev/terminology_and_structure.md +++ /dev/null @@ -1,26 +0,0 @@ -# Terminology and Structure - -## Terminology - -Some terms used throughout the project include: - -* computation graph - a data structure to represent a computation. This is basically a directed acyclic graph in which nodes are either inputs, constants or operations on other nodes. -* tracing - the technique that takes a Python function from the user and generates the corresponding computation graph in an easy-to-read format. -* bounds - before a computation graph is converted to MLIR, we need to know which node will output which type (e.g., uint3 vs euint5). Computation graphs with different inputs must remember the minimum and maximum values for each node, which is what we call bounds, and use bounds to determine the appropriate type for each node. -* circuit - the result of compilation. A circuit is made of the client and server components and has methods, everything from printing to evaluation. - -## Module structure - -In this section, we will briefly discuss the module structure of **Concrete-Numpy**. You are encouraged to check individual `.py` files to learn more. - -* Concrete - * Numpy - * dtypes - data type specifications - * values - value specifications (i.e., data type + shape + encryption status) - * representation - representation of computation - * tracing - tracing of Python functions - * extensions - custom functionality which is not available in NumPy (e.g., direct table lookups) - * MLIR - MLIR conversion - * compilation - compilation from a Python function to a circuit, client/server architecture - * ONNX - * convolution - custom convolution operations that follow the behavior of ONNX diff --git a/frontends/concrete-python/docs/getting-started/installing.md b/frontends/concrete-python/docs/getting-started/installing.md deleted file mode 100644 index 8779f9d4e..000000000 --- a/frontends/concrete-python/docs/getting-started/installing.md +++ /dev/null @@ -1,46 +0,0 @@ -# Installation - -**Concrete Python** is natively supported on Linux and macOS for Python 3.8 onwards. - -## Using PyPI - -You can install **Concrete Python** from PyPI: - -```shell -pip install -U pip wheel setuptools -pip install concrete-python -``` - -{% hint style="warning" %} -Apple Silicon is not supported for the time being. We're working on bringing support for it, which should arrive soon. -{% endhint %} - -## Using Docker - -You can also get the **Concrete Python** docker image: - -```shell -docker pull zamafhe/concrete-python:v1.0.0 -``` - -### Starting a Jupyter server. - -By default, the entry point of the **Concrete Python** docker image is a jupyter server that you can access from your browser: - -```shell -docker run --rm -it -p 8888:8888 zamafhe/concrete-python:v1.0.0 -``` - -To save notebooks on host, you can use a local volume: - -```shell -docker run --rm -it -p 8888:8888 -v /path/to/notebooks:/data zamafhe/concrete-python:v1.0.0 -``` - -### Starting a Bash session. - -Alternatively, you can launch a Bash session: - -```shell -docker run --rm -it zamafhe/concrete-python:v1.0.0 /bin/bash -``` diff --git a/frontends/concrete-python/docs/getting-started/performance.md b/frontends/concrete-python/docs/getting-started/performance.md deleted file mode 100644 index 51ebf1d65..000000000 --- a/frontends/concrete-python/docs/getting-started/performance.md +++ /dev/null @@ -1,104 +0,0 @@ -# Performance - -The most important operation in Concrete-Numpy is the table lookup operation. All operations except addition, subtraction, multiplication with non-encrypted values, and a few operations built with those primitive operations (e.g. matmul, conv) are converted to table lookups under the hood: - -```python -import concrete.numpy as cnp - -@cnp.compiler({"x": "encrypted"}) -def f(x): - return x ** 2 - -inputset = range(2 ** 4) -circuit = f.compile(inputset) -``` - -is exactly the same as - -```python -import concrete.numpy as cnp - -table = cnp.LookupTable([x ** 2 for x in range(2 ** 4)]) - -@cnp.compiler({"x": "encrypted"}) -def f(x): - return table[x] - -inputset = range(2 ** 4) -circuit = f.compile(inputset) -``` - -Table lookups are very flexible, and they allow Concrete Numpy to support many operations, but they are expensive! Therefore, you should try to avoid them as much as possible. In most cases, it's not possible to avoid them completely, but you might remove the number of TLUs or replace some of them with other primitive operations. - -The exact cost depend on many variables (machine configuration, error probability, etc.), but you can develop some intuition for single threaded CPU execution performance using: - -```python -import time - -import concrete.numpy as cnp -import numpy as np - -WARMUP = 3 -SAMPLES = 8 -BITWIDTHS = range(1, 15) -CONFIGURATION = cnp.Configuration( - enable_unsafe_features=True, - use_insecure_key_cache=True, - insecure_key_cache_location=".keys", -) - -timings = {} -for n in BITWIDTHS: - @cnp.compiler({"x": "encrypted"}) - def base(x): - return x - - table = cnp.LookupTable([np.sqrt(x).round().astype(np.int64) for x in range(2 ** n)]) - - @cnp.compiler({"x": "encrypted"}) - def tlu(x): - return table[x] - - inputset = [0, 2**n - 1] - - base_circuit = base.compile(inputset, CONFIGURATION) - tlu_circuit = tlu.compile(inputset, CONFIGURATION) - - print() - print(f"Generating keys for n={n}...") - - base_circuit.keygen() - tlu_circuit.keygen() - - timings[n] = [] - for i in range(SAMPLES + WARMUP): - sample = np.random.randint(0, 2 ** n) - - encrypted_sample = base_circuit.encrypt(sample) - start = time.time() - encrypted_result = base_circuit.run(encrypted_sample) - end = time.time() - assert base_circuit.decrypt(encrypted_result) == sample - - base_time = end - start - - encrypted_sample = tlu_circuit.encrypt(sample) - start = time.time() - encrypted_result = tlu_circuit.run(encrypted_sample) - end = time.time() - assert tlu_circuit.decrypt(encrypted_result) == np.sqrt(sample).round().astype(np.int64) - - tlu_time = end - start - - if i >= WARMUP: - timings[n].append(tlu_time - base_time) - print(f"Sample #{i - WARMUP + 1} took {timings[n][-1] * 1000:.3f}ms") - -print() -for n, times in timings.items(): - print(f"{n}-bits -> {np.mean(times) * 1000:.3f}ms") -``` - -{% hint style="info" %} -Concrete Numpy automatically parallelize execution if TLUs are applied to tensors. -{% endhint %} diff --git a/frontends/concrete-python/docs/howto/debug.md b/frontends/concrete-python/docs/howto/debug.md deleted file mode 100644 index 7b0e866e1..000000000 --- a/frontends/concrete-python/docs/howto/debug.md +++ /dev/null @@ -1,265 +0,0 @@ -# Debug - -In this section, you will learn how to debug the compilation process easily as well as how to get help in case you cannot resolve your issue. - -## Debug Artifacts - -**Concrete-Numpy** has an artifact system to simplify the process of debugging issues. - -### Automatic export. - -In case of compilation failures, artifacts are exported automatically to the `.artifacts` directory under the working directory. Let's intentionally create a compilation failure to show what kinds of things are exported. - -```python -def f(x): - return np.sin(x) -``` - -This function fails to compile because **Concrete-Numpy** does not support floating-point outputs. When you try to compile it, an exception will be raised and the artifacts will be exported automatically. If you go the `.artifacts` directory under the working directory, you'll see the following files: - -#### environment.txt - -This file contains information about your setup (i.e., your operating system and python version). - -``` -Linux-5.12.13-arch1-2-x86_64-with-glibc2.29 #1 SMP PREEMPT Fri, 25 Jun 2021 22:56:51 +0000 -Python 3.8.10 -``` - -#### requirements.txt - -This file contains information about python packages and their versions installed on your system. - -``` -alabaster==0.7.12 -appdirs==1.4.4 -argon2-cffi==21.1.0 -... -wheel==0.37.0 -widgetsnbextension==3.5.1 -wrapt==1.12.1 -``` - -#### function.txt - -This file contains information about the function you tried to compile. - -``` -def f(x): - return np.sin(x) -``` - -#### parameters.txt - -This file contains information about the encryption status of the parameters of the function you tried to compile. - -``` -x :: encrypted -``` - -#### 1.initial.graph.txt - -This file contains the textual representation of the initial computation graph right after tracing. - -``` -%0 = x # EncryptedScalar -%1 = sin(%0) # EncryptedScalar -return %1 -``` - -#### 1.initial.graph.png - -This file contains the visual representation of the initial computation graph right after tracing. - -![](../\_static/tutorials/artifacts/auto/1.initial.graph.png) - -#### 2.final.graph.txt - -This file contains the textual representation of the final computation graph right before MLIR conversion. - -``` -%0 = x # EncryptedScalar -%1 = sin(%0) # EncryptedScalar -return %1 -``` - -#### 2.final.graph.png - -This file contains the visual representation of the final computation graph right before MLIR conversion. - -![](../\_static/tutorials/artifacts/auto/2.final.graph.png) - -#### traceback.txt - -This file contains information about the error you received. - -``` -Traceback (most recent call last): - File "/home/default/Documents/Projects/Zama/hdk/concrete/numpy/compilation/compiler.py", line 320, in compile - mlir = GraphConverter.convert(self.graph) - File "/home/default/Documents/Projects/Zama/hdk/concrete/numpy/mlir/graph_converter.py", line 298, in convert - GraphConverter._check_graph_convertibility(graph) - File "/home/default/Documents/Projects/Zama/hdk/concrete/numpy/mlir/graph_converter.py", line 175, in _check_graph_convertibility - raise RuntimeError(message) -RuntimeError: Function you are trying to compile cannot be converted to MLIR - -%0 = x # EncryptedScalar -%1 = sin(%0) # EncryptedScalar -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ only integer operations are supported -return %1 -``` - -### Manual export. - -Manual exports are mostly used for visualization. Nonetheless, they can be very useful for demonstrations. Here is how to perform one: - -```python -import concrete.numpy as cnp -import numpy as np - -artifacts = cnp.DebugArtifacts("/tmp/custom/export/path") - -@cnp.compiler({"x": "encrypted"}) -def f(x): - return 127 - (50 * (np.sin(x) + 1)).astype(np.int64) - -inputset = range(2 ** 3) -circuit = f.compile(inputset, artifacts=artifacts) - -artifacts.export() -``` - -If you go to the `/tmp/custom/export/path` directory, you'll see the following files: - -#### 1.initial.graph.txt - -This file contains the textual representation of the initial computation graph right after tracing. - -``` -%0 = 127 # ClearScalar -%1 = 50 # ClearScalar -%2 = 1 # ClearScalar -%3 = x # EncryptedScalar -%4 = sin(%3) # EncryptedScalar -%5 = add(%4, %2) # EncryptedScalar -%6 = multiply(%1, %5) # EncryptedScalar -%7 = astype(%6, dtype=int_) # EncryptedScalar -%8 = subtract(%0, %7) # EncryptedScalar -return %8 -``` - -#### 1.initial.graph.png - -This file contains the visual representation of the initial computation graph right after tracing. - -![](../\_static/tutorials/artifacts/manual/1.initial.graph.png) - -#### 2.after-float-fuse-0.graph.txt - -This file contains the textual representation of the intermediate computation graph after fusing. - -``` -%0 = 127 # ClearScalar -%1 = x # EncryptedScalar -%2 = subgraph(%1) # EncryptedScalar -%3 = subtract(%0, %2) # EncryptedScalar -return %3 - -Subgraphs: - - %2 = subgraph(%1): - - %0 = 50 # ClearScalar - %1 = 1 # ClearScalar - %2 = input # EncryptedScalar - %3 = sin(%2) # EncryptedScalar - %4 = add(%3, %1) # EncryptedScalar - %5 = multiply(%0, %4) # EncryptedScalar - %6 = astype(%5, dtype=int_) # EncryptedScalar - return %6 -``` - -#### 2.after-fusing.graph.png - -This file contains the visual representation of the intermediate computation graph after fusing. - -![](../\_static/tutorials/artifacts/manual/2.after-fusing.graph.png) - -#### 3.final.graph.txt - -This file contains the textual representation of the final computation graph right before MLIR conversion. - -``` -%0 = 127 # ClearScalar -%1 = x # EncryptedScalar -%2 = subgraph(%1) # EncryptedScalar -%3 = subtract(%0, %2) # EncryptedScalar -return %3 - -Subgraphs: - - %2 = subgraph(%1): - - %0 = 50 # ClearScalar - %1 = 1 # ClearScalar - %2 = input # EncryptedScalar - %3 = sin(%2) # EncryptedScalar - %4 = add(%3, %1) # EncryptedScalar - %5 = multiply(%0, %4) # EncryptedScalar - %6 = astype(%5, dtype=int_) # EncryptedScalar - return %6 -``` - -#### 3.final.graph.png - -This file contains the visual representation of the final computation graph right before MLIR conversion. - -![](../\_static/tutorials/artifacts/manual/3.final.graph.png) - -#### bounds.txt - -This file contains information about the bounds of the final computation graph of the function you are compiling using the inputset you provide. - -``` -%0 :: [127, 127] -%1 :: [0, 7] -%2 :: [2, 95] -%3 :: [32, 125] -``` - -#### mlir.txt - -This file contains information about the MLIR of the function you compiled using the inputset you provided. - -``` -module { - func @main(%arg0: !FHE.eint<7>) -> !FHE.eint<7> { - %c127_i8 = arith.constant 127 : i8 - %cst = arith.constant dense<"..."> : tensor<128xi64> - %0 = "FHE.apply_lookup_table"(%arg0, %cst) : (!FHE.eint<7>, tensor<128xi64>) -> !FHE.eint<7> - %1 = "FHE.sub_int_eint"(%c127_i8, %0) : (i8, !FHE.eint<7>) -> !FHE.eint<7> - return %1 : !FHE.eint<7> - } -} -``` - -## Asking the community - -You can seek help with your issue by asking a question directly in the [community forum](https://community.zama.ai/). - -## Submitting an issue - -If you cannot find a solution in the community forum, or you found a bug in the library, you could create an issue in our GitHub repository. - -In case of a bug: - -* try to minimize randomness -* try to minimize your function as much as possible while keeping the bug - this will help to fix the bug faster -* try to include your inputset in the issue -* try to include reproduction steps in the issue -* try to include debug artifacts in the issue - -In case of a feature request: - -* try to give a minimal example of the desired behavior -* try to explain your use case diff --git a/frontends/concrete-python/docs/linux.dependency.licenses.txt b/frontends/concrete-python/docs/linux.dependency.licenses.txt deleted file mode 100644 index c07c3aa7a..000000000 --- a/frontends/concrete-python/docs/linux.dependency.licenses.txt +++ /dev/null @@ -1,21 +0,0 @@ - Name Version License - Pillow 9.4.0 Historical Permission Notice and Disclaimer (HPND) - PyYAML 6.0 MIT License - concrete-compiler 0.24.0rc5 BSD-3 - cycler 0.11.0 BSD License - fonttools 4.38.0 MIT License - kiwisolver 1.4.4 BSD License - matplotlib 3.5.3 Python Software Foundation License - networkx 2.6.3 BSD License - numpy 1.24.2 BSD License - nvidia-cublas-cu11 11.10.3.66 Other/Proprietary License - nvidia-cuda-nvrtc-cu11 11.7.99 Other/Proprietary License - nvidia-cuda-runtime-cu11 11.7.99 Other/Proprietary License - nvidia-cudnn-cu11 8.5.0.96 Other/Proprietary License - packaging 23.0 Apache Software License; BSD License - pyparsing 3.0.9 MIT License - python-dateutil 2.8.2 Apache Software License; BSD License - scipy 1.10.1 BSD License - six 1.16.0 MIT License - torch 1.13.1 BSD License - typing-extensions 3.10.0.2 Python Software Foundation License diff --git a/frontends/concrete-python/docs/tutorial/extensions.md b/frontends/concrete-python/docs/tutorial/extensions.md deleted file mode 100644 index 3b5b40fe0..000000000 --- a/frontends/concrete-python/docs/tutorial/extensions.md +++ /dev/null @@ -1,153 +0,0 @@ -# Extensions - -**Concrete-Numpy** tries to support **NumPy** as much as possible, but due to some technical limitations, not everything can be supported. On top of that, there are some things **NumPy** lack, which are useful. In some of these situations, we provide extensions in **Concrete-Numpy** to improve your experience. - -## cnp.zero() - -Allows you to create encrypted scalar zero: - -```python -import concrete.numpy as cnp -import numpy as np - -@cnp.compiler({"x": "encrypted"}) -def f(x): - z = cnp.zero() - return x + z - -inputset = range(10) -circuit = f.compile(inputset) - -for x in range(10): - assert circuit.encrypt_run_decrypt(x) == x -``` - -## cnp.zeros(shape) - -Allows you to create encrypted tensor of zeros: - -```python -import concrete.numpy as cnp -import numpy as np - -@cnp.compiler({"x": "encrypted"}) -def f(x): - z = cnp.zeros((2, 3)) - return x + z - -inputset = range(10) -circuit = f.compile(inputset) - -for x in range(10): - assert np.array_equal(circuit.encrypt_run_decrypt(x), np.array([[x, x, x], [x, x, x]])) -``` - -## cnp.one() - -Allows you to create encrypted scalar one: - -```python -import concrete.numpy as cnp -import numpy as np - -@cnp.compiler({"x": "encrypted"}) -def f(x): - z = cnp.one() - return x + z - -inputset = range(10) -circuit = f.compile(inputset) - -for x in range(10): - assert circuit.encrypt_run_decrypt(x) == x + 1 -``` - -## cnp.ones(shape) - -Allows you to create encrypted tensor of ones: - -```python -import concrete.numpy as cnp -import numpy as np - -@cnp.compiler({"x": "encrypted"}) -def f(x): - z = cnp.ones((2, 3)) - return x + z - -inputset = range(10) -circuit = f.compile(inputset) - -for x in range(10): - assert np.array_equal(circuit.encrypt_run_decrypt(x), np.array([[x, x, x], [x, x, x]]) + 1) -``` - -## cnp.univariate(function) - -Allows you to wrap any univariate function into a single table lookup: - -```python -import concrete.numpy as cnp -import numpy as np - -def complex_univariate_function(x): - - def per_element(element): - result = 0 - for i in range(element): - result += i - return result - - return np.vectorize(per_element)(x) - -@cnp.compiler({"x": "encrypted"}) -def f(x): - return cnp.univariate(complex_univariate_function)(x) - -inputset = [np.random.randint(0, 5, size=(3, 2)) for _ in range(10)] -circuit = f.compile(inputset) - -sample = np.array([ - [0, 4], - [2, 1], - [3, 0], -]) -assert np.array_equal(circuit.encrypt_run_decrypt(sample), complex_univariate_function(sample)) -``` - -{% hint style="danger" %} -The wrapped function shouldn't have any side effects, and it should be deterministic. -{% endhint %} - -## coonx.conv(...) - -Allows you to perform a convolution operation, with the same semantic of [onnx.Conv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Conv): - -```python -import concrete.numpy as cnp -import concrete.onnx as connx -import numpy as np - -weight = np.array([[2, 1], [3, 2]]).reshape(1, 1, 2, 2) - -@cnp.compiler({"x": "encrypted"}) -def f(x): - return connx.conv(x, weight, strides=(2, 2), dilations=(1, 1), group=1) - -inputset = [np.random.randint(0, 4, size=(1, 1, 4, 4)) for _ in range(10)] -circuit = f.compile(inputset) - -sample = np.array( - [ - [3, 2, 1, 0], - [3, 2, 1, 0], - [3, 2, 1, 0], - [3, 2, 1, 0], - ] -).reshape(1, 1, 4, 4) -assert np.array_equal(circuit.encrypt_run_decrypt(sample), f(sample)) -``` - -{% hint style="danger" %} -Only 2D convolutions with one groups and without padding are supported for the time being. -{% endhint %}