Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doc review: Combining compiled functions #1011

Merged
merged 1 commit into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions docs/compilation/combining.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Combining compiled functions

In various cases, deploying a server that contains many compatible functions is important. By compatible, we mean that the functions will be used together, with outputs of some of them being used as inputs of some other ones, without decryption in the middle. It also encompasses the use of recursive functions.
This document explains how to combine compiled functions in **Concrete**, focusing on scenarios where multiple functions need to work together seamlessly. The goal is to ensure that outputs from certain functions can be used as inputs for others without decryption, including in recursive functions.

**Concrete** offers two methods to achieve this:

- **Using the `composable` flag**: This method is suitable when there is a single function. The composable flag allows the function to be compiled in a way that its output can be used as input for subsequent operations. For more details, refer to the [composition documentation](composition.md).

- **Using Concrete modules**: This method is ideal when dealing with multiple functions or when more control is needed over how outputs are reused as inputs. Concrete modules allow you to specify precisely how functions interact. For further information, see the [modules documentation](composing_functions_with_modules.md).

To support this feature in Concrete, we have two ways:
- using the `composable` flag in the compilation, when there is a unique function. This option is described in [this document](composition.md)
- using the Concrete modules, when there are several functions, or when there is a unique function for which we want to more precisely detail how outputs are reused as further inputs. This functionality is described in [this document](composing_functions_with_modules.md)
15 changes: 7 additions & 8 deletions docs/compilation/composing_functions_with_modules.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Composing functions with modules

This document explains how to compile Fully Homomorphic Encryption (FHE) modules containing multiple functions using Concrete.
This document explains how to compile Fully Homomorphic Encryption (FHE) modules containing multiple functions using **Concrete**.

Deploying a server that contains many compatible functions is important for some use cases. With Concrete, you can compile FHE modules containing as many functions as needed.
Deploying a server that contains many compatible functions is important for some use cases. With **Concrete**, you can compile FHE modules containing as many functions as needed.

These modules support the composition of different functions, meaning that the encrypted result of one function can be used as the input for another function without needing to decrypt it first. Additionally, a module is [deployed in a single artifact](../guides/deploy.md#deployment-of-modules), making it as simple to use as a single-function project.

Expand All @@ -23,7 +23,7 @@ class Counter:
return x - 1 % 20
```

Then, you can compile the FHE module `Counter` using the `compile` method. To do that, you need to provide a dictionary of input-sets for every function:
Then, to compile the `Counter` module, use the `compile` method with a dictionary of input-sets for each function:

```python
inputset = list(range(20))
Expand All @@ -49,7 +49,7 @@ x_dec = CounterFhe.inc.decrypt(x_enc)
assert x_dec == 15
```

The keyset can be generated beforehand by calling `keygen()` method on the compiled module:
You can generate the keyset beforehand by calling `keygen()` method on the compiled module:

```python
CounterFhe.keygen()
Expand Down Expand Up @@ -115,16 +115,15 @@ Encrypting initial values
| 9 || 144 | 144 | 233 | 233 |
```

## Iterations
## Iterations

With the previous example, we see that modules allow iteration with cleartext iterands to some extent. Specifically, loops with the following structure are supported:
Modules support iteration with cleartext iterands to some extent, particularly for loops structured like this:

```python
for i in some_cleartext_constant_range:
# Do something in FHE in the loop body, implemented as an FHE function.
```

With this pattern, we can also support unbounded loops or complex dynamic condition, as long as this condition is computed in pure cleartext python. Here is an example that computes the [Collatz sequence](https://en.wikipedia.org/wiki/Collatz_conjecture):
Unbounded loops or complex dynamic conditions are also supported, as long as these conditions are computed in pure cleartext in Python. The following example computes the [Collatz sequence](https://en.wikipedia.org/wiki/Collatz_conjecture):

```python
from concrete import fhe
Expand Down
9 changes: 6 additions & 3 deletions docs/compilation/composition.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Combining compiled functions with the composable flag

A simple way to say that a function `f` should be compiled such that its outputs can be reused as inputs is to use the
[`composable`](../guides/configure.md#options) configuration setting to `True` when compiling. Doing so, we can then easily compute `f(f(x))` or `f**i(x) = f(f(...(f(x) ..))` for a variable non-encrypted integer `i`, which is typically what happens for recursions.
This document explains how to combine compiled functions with the `composable` flag in **Concrete**.

By setting the `composable` flag to `True`, you can compile a function such that its outputs can be reused as inputs. For example, you can then easily compute `f(f(x))` or `f**i(x) = f(f(...(f(x) ..))` for a non-encrypted integer `i` variable, which is usually required for recursions.

Here is an example:

```python
from concrete import fhe
Expand Down Expand Up @@ -30,7 +33,7 @@ for i in range(10):
print(f"| {i} || {counter_dec:<9} | {counter:<9} |")
```

Remark that this option is the equivalent of using the `fhe.AllComposable` policy of [modules](composing_functions_with_modules.md). In particular, the same limitations may occur (see [limitations documentation](composing_functions_with_modules.md#limitations) section).
Remark that this option is the equivalent to using the `fhe.AllComposable` policy of [modules](composing_functions_with_modules.md). In particular, the same limitations may occur (see [limitations documentation](composing_functions_with_modules.md#limitations) section).



Loading