> For the complete documentation index, see [llms.txt](https://docs.zama.org/concrete/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.zama.org/concrete/2.7-1/developers/dialects/fhelinalgdialect.md).

# FHELinalg dialect

High Level Fully Homomorphic Encryption Linalg dialect A dialect for representation of high level linalg operations on fully homomorphic ciphertexts.

## Operation definition

### `FHELinalg.add_eint_int` (::mlir::concretelang::FHELinalg::AddEintIntOp)

Returns a tensor that contains the addition of a tensor of encrypted integers and a tensor of clear integers.

Performs an addition following the broadcasting rules between a tensor of encrypted integers and a tensor of clear integers. The width of the clear integers must be less than or equal to the width of encrypted integers.

Examples:

```mlir
// Returns the term-by-term addition of `%a0` with `%a1`
"FHELinalg.add_eint_int"(%a0, %a1) : (tensor<4x!FHE.eint<4>>, tensor<4xi5>) -> tensor<4x!FHE.eint<4>>

// Returns the term-by-term addition of `%a0` with `%a1`, where dimensions equal to one are stretched.
"FHELinalg.add_eint_int"(%a0, %a1) : (tensor<4x1x4x!FHE.eint<4>>, tensor<1x4x4xi5>) -> tensor<4x4x4x!FHE.eint<4>>

// Returns the addition of a 3x3 matrix of encrypted integers and a 3x1 matrix (a column) of integers.
//
// [1,2,3]   [1]   [2,3,4]
// [4,5,6] + [2] = [6,7,8]
// [7,8,9]   [3]   [10,11,12]
//
// The dimension #1 of operand #2 is stretched as it is equal to 1.
"FHELinalg.add_eint_int"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<3x1xi5>) -> tensor<3x3x!FHE.eint<4>>

// Returns the addition of a 3x3 matrix of encrypted integers and a 1x3 matrix (a line) of integers.
//
// [1,2,3]             [2,4,6]
// [4,5,6] + [1,2,3] = [5,7,9]
// [7,8,9]             [8,10,12]
//
// The dimension #2 of operand #2 is stretched as it is equal to 1.
"FHELinalg.add_eint_int"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<1x3xi5>) -> tensor<3x3x!FHE.eint<4>>

// Same behavior as the previous one, but as the dimension #2 is missing of operand #2.
"FHELinalg.add_eint_int(%a0, %a1)" : (tensor<3x4x!FHE.eint<4>>, tensor<3xi5>) -> tensor<4x4x4x!FHE.eint<4>>

```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEintInt, TensorBroadcastingRules

Interfaces: Binary, BinaryEintInt, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.add_eint` (::mlir::concretelang::FHELinalg::AddEintOp)

Returns a tensor that contains the addition of two tensor of encrypted integers.

Performs an addition following the broadcasting rules between two tensors of encrypted integers. The width of the encrypted integers must be equal.

Examples:

```mlir
// Returns the term-by-term addition of `%a0` with `%a1`
"FHELinalg.add_eint"(%a0, %a1) : (tensor<4x!FHE.eint<4>>, tensor<4x!FHE.eint<4>>) -> tensor<4x!FHE.eint<4>>

// Returns the term-by-term addition of `%a0` with `%a1`, where dimensions equal to one are stretched.
"FHELinalg.add_eint"(%a0, %a1) : (tensor<4x1x4x!FHE.eint<4>>, tensor<1x4x4x!FHE.eint<4>>) -> tensor<4x4x4x!FHE.eint<4>>

// Returns the addition of a 3x3 matrix of encrypted integers and a 3x1 matrix (a column) of encrypted integers.
//
// [1,2,3]   [1]   [2,3,4]
// [4,5,6] + [2] = [6,7,8]
// [7,8,9]   [3]   [10,11,12]
//
// The dimension #1 of operand #2 is stretched as it is equal to 1.
"FHELinalg.add_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<3x1x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>

// Returns the addition of a 3x3 matrix of encrypted integers and a 1x3 matrix (a line) of encrypted integers.
//
// [1,2,3]             [2,4,6]
// [4,5,6] + [1,2,3] = [5,7,9]
// [7,8,9]             [8,10,12]
//
// The dimension #2 of operand #2 is stretched as it is equal to 1.
"FHELinalg.add_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<1x3x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>

// Same behavior as the previous one, but as the dimension #2 of operand #2 is missing.
"FHELinalg.add_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<3x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>
```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEint, TensorBroadcastingRules

Interfaces: BinaryEint, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.apply_lookup_table` (::mlir::concretelang::FHELinalg::ApplyLookupTableEintOp)

Returns a tensor that contains the result of the lookup on a table.

For each encrypted index, performs a lookup table of clear integers.

```mlir
// The result of this operation, is a tensor that contains the result of a lookup table.
// i.e. %res[i, ..., k] = %lut[%t[i, ..., k]]
%res = FHELinalg.apply_lookup_table(%t, %lut): tensor<DNx...xD1x!FHE.eint<$p>>, tensor<D2^$pxi64> -> tensor<DNx...xD1x!FHE.eint<$p>>
```

The `%lut` argument must be a tensor with one dimension, where its dimension is `2^p` where `p` is the width of the encrypted integers.

Examples:

```mlir

// Returns the lookup of 3x3 matrix of encrypted indices of with 2 on a table of size 4=2² of clear integers.
//
// [0,1,2]                 [1,3,5]
// [3,0,1] lut [1,3,5,7] = [7,1,3]
// [2,3,0]                 [5,7,1]
"FHELinalg.apply_lookup_table"(%t, %lut) : (tensor<3x3x!FHE.eint<2>>, tensor<4xi64>) -> tensor<3x3x!FHE.eint<3>>
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, ConstantNoise, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|   `t`   |             |
|  `lut`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.apply_mapped_lookup_table` (::mlir::concretelang::FHELinalg::ApplyMappedLookupTableEintOp)

Returns a tensor that contains the result of the lookup on a table, using a different lookup table for each element, specified by a map.

Performs for each encrypted index a lookup table of clear integers. Multiple lookup tables are passed, and the application of lookup tables is performed following the broadcasting rules. The precise lookup is specified by a map.

```mlir
// The result of this operation, is a tensor that contains the result of the lookup on different tables.
// i.e. %res[i, ..., k] = %luts[ %map[i, ..., k] ][ %t[i, ..., k] ]
%res = FHELinalg.apply_mapped_lookup_table(%t, %luts, %map): tensor<DNx...xD1x!FHE.eint<$p>>, tensor<DM x ^$p>, tensor<DNx...xD1xindex> -> tensor<DNx...xD1x!FHE.eint<$p>>
```

Examples:

```mlir

// Returns the lookup of 3x2 matrix of encrypted indices of width 2 on a vector of 2 tables of size 4=2^2 of clear integers.
//
// [0,1]                                 [0, 1] = [1,2]
// [3,0] lut [[1,3,5,7], [0,2,4,6]] with [0, 1] = [7,0]
// [2,3]                                 [0, 1] = [5,6]
"FHELinalg.apply_mapped_lookup_table"(%t, %luts, %map) : (tensor<3x2x!FHE.eint<2>>, tensor<2x4xi64>, tensor<3x2xindex>) -> tensor<3x2x!FHE.eint<3>>
```

Others examples: // \[0,1] \[1, 0] = \[3,2] // \[3,0] lut \[\[1,3,5,7], \[0,2,4,6]] with \[0, 1] = \[7,0] // \[2,3] \[1, 0] = \[4,7]

// \[0,1] \[0, 0] = \[1,3] // \[3,0] lut \[\[1,3,5,7], \[0,2,4,6]] with \[1, 1] = \[6,0] // \[2,3] \[1, 0] = \[4,7]

// \[0,1] \[0] = \[1,3] // \[3,0] lut \[\[1,3,5,7], \[0,2,4,6]] with \[1] = \[6,0] // \[2,3] \[0] = \[5,7]

// \[0,1] = \[1,2] // \[3,0] lut \[\[1,3,5,7], \[0,2,4,6]] with \[0, 1] = \[7,0] // \[2,3] = \[5,6]

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, ConstantNoise, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|   `t`   |             |
|  `luts` |             |
|  `map`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.apply_multi_lookup_table` (::mlir::concretelang::FHELinalg::ApplyMultiLookupTableEintOp)

Returns a tensor that contains the result of the lookup on a table, using a different lookup table for each element.

Performs for each encrypted index a lookup table of clear integers. Multiple lookup tables are passed, and the application of lookup tables is performed following the broadcasting rules.

```mlir
// The result of this operation, is a tensor that contains the result of the lookup on different tables.
// i.e. %res[i, ..., k] = [ %luts[i][%t[i]], ..., %luts[k][%t[k]] ]
%res = FHELinalg.apply_multi_lookup_table(%t, %lut): tensor<DNx...xD1x!FHE.eint<$p>>, tensor<DMx...xD1xD2^$pxi64> -> tensor<DNx...xD1x!FHE.eint<$p>>
```

The `%luts` argument should be a tensor with M dimension, where the first M-1 dimensions are broadcastable with the N dimensions of the encrypted tensor, and where the last dimension dimension is equal to `2^p` where `p` is the width of the encrypted integers.

Examples:

```mlir

// Returns the lookup of 3x2 matrix of encrypted indices of width 2 on a vector of 2 tables of size 4=2² of clear integers.
// The tables are broadcasted along the first dimension of the tensor.
//
// [0,1]                            = [1,2]
// [3,0] lut [[1,3,5,7], [0,2,4,6]] = [7,0]
// [2,3]                            = [5,6]
"FHELinalg.apply_multi_lookup_table"(%t, %luts) : (tensor<3x2x!FHE.eint<2>>, tensor<2x4xi64>) -> tensor<3x2x!FHE.eint<3>>
```

```mlir

// Returns the lookup of a vector of 3 encrypted indices of width 2 on a vector of 3 tables of size 4=2² of clear integers.
//
// [3,0,1] lut [[1,3,5,7], [0,2,4,6], [1,2,3,4]] = [7,0,2]
"FHELinalg.apply_multi_lookup_table"(%t, %luts) : (tensor<3x!FHE.eint<2>>, tensor<3x4xi64>) -> tensor<3x!FHE.eint<3>>
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, ConstantNoise, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|   `t`   |             |
|  `luts` |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.broadcast` (::mlir::concretelang::FHELinalg::BroadcastOp)

Broadcasts a tensor to a shape.

Broadcasting is used for expanding certain dimensions of a tensor or adding new dimensions to it at the beginning.

An example could be broadcasting a tensor with shape <1x2x1x4x1> to a tensor of shape <6x1x2x3x4x5>.

In this example:

* last dimension of the input (1) is expanded to (5)
* the dimension before that (4) is kept
* the dimension before that (1) is expanded to (3)
* the dimension before that (2) is kept
* the dimension before that (1) is kept
* a new dimension (6) is added to the beginning

See <https://numpy.org/doc/stable/user/basics.broadcasting.html#general-broadcasting-rules> for the semantics of broadcasting.

Examples:

```mlir
"FHELinalg.broadcast"(%t) : (tensor<1xindex>) -> tensor<3xindex>
//
// broadcast([5]) = [5, 5, 5]
//
```

```mlir
"FHELinalg.broadcast"(%t) : (tensor<1xindex>) -> tensor<3x2xindex>
//
// broadcast([5]) = [[5, 5], [5, 5], [5, 5]]
//
```

```mlir
"FHELinalg.broadcast"(%t) : (tensor<2xindex>) -> tensor<3x2xindex>
//
// broadcast([2, 6]) = [[2, 6], [2, 6], [2, 6]]
//
```

```mlir
"FHELinalg.broadcast"(%t) : (tensor<3x1xindex>) -> tensor<3x2xindex>
//
// broadcast([[1], [2], [3]]) = [[1, 1], [2, 2], [3, 3]]
//
```

```mlir
"FHELinalg.broadcast"(%t) : (tensor<2xindex>) -> tensor<2x3x2xindex>
//
// broadcast([2, 6]) = [[[2, 6], [2, 6], [2, 6]], [[2, 6], [2, 6], [2, 6]]]
//
```

```mlir
"FHELinalg.broadcast"(%t) : (tensor<3x1xindex>) -> tensor<2x3x2xindex>
//
// broadcast([[1], [2], [3]]) = [[[1, 1], [2, 2], [3, 3]], [[1, 1], [2, 2], [3, 3]]]
//
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, ConstantNoise, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` |             |

#### Results:

|  Result  | Description |
| :------: | ----------- |
| `output` |             |

### `FHELinalg.concat` (::mlir::concretelang::FHELinalg::ConcatOp)

Concatenates a sequence of tensors along an existing axis.

Concatenates several tensors along a given axis.

Examples:

```mlir
"FHELinalg.concat"(%a, %b) { axis = 0 } : (tensor<3x3x!FHE.eint<4>>, tensor<3x3x!FHE.eint<4>>) -> tensor<6x3x!FHE.eint<4>>
//
//        ( [1,2,3]  [1,2,3] )   [1,2,3]
// concat ( [4,5,6], [4,5,6] ) = [4,5,6]
//        ( [7,8,9]  [7,8,9] )   [7,8,9]
//                               [1,2,3]
//                               [4,5,6]
//                               [7,8,9]
//
```

```mlir
"FHELinalg.concat"(%a, %b) { axis = 1 } : (tensor<3x3x!FHE.eint<4>>, tensor<3x3x!FHE.eint<4>>) -> tensor<3x6x!FHE.eint<4>>
//
//        ( [1,2,3]  [1,2,3] )   [1,2,3,1,2,3]
// concat ( [4,5,6], [4,5,6] ) = [4,5,6,4,5,6]
//        ( [7,8,9]  [7,8,9] )   [7,8,9,7,8,9]
//
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Attributes:

| Attribute |      MLIR Type      | Description                       |
| :-------: | :-----------------: | --------------------------------- |
|   `axis`  | ::mlir::IntegerAttr | 64-bit signless integer attribute |

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `ins`  |             |

#### Results:

| Result | Description |
| :----: | ----------- |
|  `out` |             |

### `FHELinalg.conv2d` (::mlir::concretelang::FHELinalg::Conv2dOp)

Returns the 2D convolution of a tensor in the form NCHW with weights in the form FCHW

Traits: AlwaysSpeculatableImplTrait

Interfaces: Binary, BinaryEintInt, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Attributes:

|  Attribute  |           MLIR Type          | Description                                |
| :---------: | :--------------------------: | ------------------------------------------ |
|  `padding`  | ::mlir::DenseIntElementsAttr | 64-bit signless integer elements attribute |
|  `strides`  | ::mlir::DenseIntElementsAttr | 64-bit signless integer elements attribute |
| `dilations` | ::mlir::DenseIntElementsAttr | 64-bit signless integer elements attribute |
|   `group`   |      ::mlir::IntegerAttr     | 64-bit signless integer attribute          |

#### Operands:

|  Operand | Description |
| :------: | ----------- |
|  `input` |             |
| `weight` |             |
|  `bias`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.dot_eint_int` (::mlir::concretelang::FHELinalg::Dot)

Returns the encrypted dot product between a vector of encrypted integers and a vector of clean integers.

Performs a dot product between a vector of encrypted integers and a vector of clear integers.

Examples:

```mlir
// Returns the dot product of `%a0` with `%a1`
"FHELinalg.dot_eint_int"(%a0, %a1) : (tensor<4x!FHE.eint<4>>, tensor<4xi5>) -> !FHE.eint<4>

```

Traits: AlwaysSpeculatableImplTrait

Interfaces: Binary, BinaryEintInt, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

| Result | Description |
| :----: | ----------- |
|  `out` |             |

### `FHELinalg.dot_eint_eint` (::mlir::concretelang::FHELinalg::DotEint)

Returns the encrypted dot product between two vectors of encrypted integers.

Performs a dot product between two vectors of encrypted integers.

Examples:

```mlir
// Returns the dot product of `%a0` with `%a1`
"FHELinalg.dot_eint_eint"(%a0, %a1) : (tensor<4x!FHE.eint<4>>, tensor<4x!FHE.eint<4>>) -> !FHE.eint<4>

```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

| Result | Description |
| :----: | ----------- |
|  `out` |             |

### `FHELinalg.fancy_assign` (::mlir::concretelang::FHELinalg::FancyAssignOp)

Assigns a tensor into another tensor at a tensor of indices.

Examples:

```mlir
"FHELinalg.fancy_assign"(%t, %i, %a) : (tensor<5x!FHE.eint<16>>, tensor<3xindex>, tensor<3x!FHE.eint<16>>) -> tensor<5x!FHE.eint<16>>
//
// fancy_assign([10, 20, 30, 40, 50], [3, 1, 2], [1000, 2000, 3000]) = [10, 2000, 3000, 1000, 50]
//
```

```mlir
"FHELinalg.fancy_assign"(%t, %i, %a) : (tensor<5x!FHE.eint<16>>, tensor<2x2xindex>, tensor<2x2x!FHE.eint<16>>) -> tensor<5x!FHE.eint<16>>
//
// fancy_assign([10, 20, 30, 40, 50], [[3, 1], [2, 0]], [[1000, 2000], [3000, 4000]]) = [4000, 2000, 3000, 1000, 50]
//
```

```mlir
"FHELinalg.fancy_assign"(%t, %i, %a) : (tensor<2x3x!FHE.eint<16>>, tensor<3x2xindex>, tensor<3x!FHE.eint<16>>) -> tensor<2x3x!FHE.eint<16>>
//
// fancy_assign([[11, 12, 13], [21, 22, 23]], [[1, 0], [0, 2], [0, 0]], [1000, 2000, 3000]) = [[3000, 2000, 13], [1000, 22, 23]]
//
```

```mlir
"FHELinalg.fancy_assign"(%t, %i, %a) : (tensor<3x3x!FHE.eint<16>>, tensor<2x3x2xindex>, tensor<2x3x!FHE.eint<16>>) -> tensor<3x3x!FHE.eint<16>>
//
// fancy_assign(
//     [[11, 12, 13], [21, 22, 23], [31, 32, 33]],
//     [[[1, 0], [0, 2], [0, 0]], [[2, 0], [1, 1], [2, 1]]],
//     [[1000, 2000, 3000], [4000, 5000, 6000]]
// ) = [[3000, 2000, 13], [1000, 5000, 23], [4000, 6000, 33]]
//
```

Notes:

* Assigning to the same output position results in undefined behavior.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

|  Operand  | Description |
| :-------: | ----------- |
|  `input`  |             |
| `indices` |             |
|  `values` |             |

#### Results:

|  Result  | Description |
| :------: | ----------- |
| `output` |             |

### `FHELinalg.fancy_index` (::mlir::concretelang::FHELinalg::FancyIndexOp)

Index into a tensor using a tensor of indices.

Examples:

```mlir
"FHELinalg.fancy_index"(%t, %i) : (tensor<5x!FHE.eint<6>>, tensor<3xindex>) -> tensor<3x!FHE.eint<6>>
//
// fancy_index([10, 20, 30, 40, 50], [3, 1, 2]) = [40, 20, 30]
//
```

```mlir
"FHELinalg.fancy_index"(%t, %i) : (tensor<5x!FHE.eint<6>>, tensor<3x2xindex>) -> tensor<3x2x!FHE.eint<6>>
//
// fancy_index([10, 20, 30, 40, 50], [[3, 1], [2, 2], [0, 4]]) = [[40, 20], [30, 30], [10, 50]]
//
```

```mlir
"FHELinalg.fancy_index"(%t, %i) : (tensor<2x3x!FHE.eint<6>>, tensor<3x2xindex>) -> tensor<3x!FHE.eint<6>>
//
// fancy_index([[11, 12, 13], [21, 22, 23]], [[1, 0], [0, 2], [0, 0]]) = [21, 13, 11]
//
```

```mlir
"FHELinalg.fancy_index"(%t, %i) : (tensor<3x3x!FHE.eint<6>>, tensor<2x3x2xindex>) -> tensor<2x3x!FHE.eint<6>>
//
// fancy_index([[11, 12, 13], [21, 22, 23], [31, 32, 33]], [[[1, 0], [0, 2], [0, 0]], [[2, 0], [1, 1], [2, 1]]]) = [[21, 13, 11], [31, 22, 32]]
//
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

|  Operand  | Description |
| :-------: | ----------- |
|  `input`  |             |
| `indices` |             |

#### Results:

|  Result  | Description |
| :------: | ----------- |
| `output` |             |

### `FHELinalg.from_element` (::mlir::concretelang::FHELinalg::FromElementOp)

Creates a tensor with a single element.

Creates a tensor with a single element.

```mlir
"FHELinalg.from_element"(%a) : (Type) -> tensor<1xType>
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

|  Operand  | Description |
| :-------: | ----------- |
| «unnamed» | any type    |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.lsb` (::mlir::concretelang::FHELinalg::LsbEintOp)

Extract the lowest significant bit at a given precision.

This operation extracts the lsb of a ciphertext tensor in a specific precision.

Extracting only 1 bit:

````mlir
 // ok
 %lsb = "FHE.lsb"(%a): (tensor<1x!FHE.eint<4>)) -> (tensor<1x!FHE.eint<1>>)

If you need to clear the lsb of the original ciphertext, you should extract to the same precision as the ciphertext.
If you need to extract several bits, you can extract sequentially using explicit bitwidth change and bit clearing.

Example:
```mlir
 // ok
 %a_lsb = "FHELinalg.lsb"(%a): (tensor<1x!FHE.eint<4>)) -> (tensor<1x!FHE.eint<4>))
 %a_lsb_cleared = "FHELinalg.sub_eint"(%a, %lsb) : (tensor<1x!FHE.eint<4>), tensor<1x!FHE.eint<4>)) -> (tensor<1x!FHE.eint<4>))
 %b = %a : tensor<1x!FHE.eint<3>>
 // now you can extract the next lsb from %b
 %b_lsb = "FHELinalg.lsb"(%b): (tensor<1x!FHE.eint<3>>) -> (tensor<1x!FHE.eint<3>>)
 // later if you need %b_lsb at the original position
 %b_lsb_as_in_a = %b_lsb : tensor<1x!FHE.eint<3>>
````

Traits: AlwaysSpeculatableImplTrait, TensorUnaryEint

Interfaces: ConditionallySpeculatable, ConstantNoise, NoMemoryEffect (MemoryEffectOpInterface), UnaryEint

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` |             |

#### Results:

|  Result  | Description |
| :------: | ----------- |
| `output` |             |

### `FHELinalg.matmul_eint_eint` (::mlir::concretelang::FHELinalg::MatMulEintEintOp)

Returns a tensor that contains the result of the matrix multiplication of a matrix of encrypted integers and a second matrix of encrypted integers.

Performs a matrix multiplication of a matrix of encrypted integers and a second matrix of encrypted integers.

The behavior depends on the arguments in the following way:

```
- If both arguments are 2-D,
  they are multiplied like conventional matrices.

  e.g.,

  arg0: tensor<MxN> = [...]
  arg1: tensor<NxP> = [...]

  result: tensor<MxP> = [...]

- If the first argument is a vector (1-D),
  it is treated as a matrix with a single row and standard matrix multiplication is performed.

  After standard matrix multiplication,
  the first dimension is removed from the result.

  e.g.,

  arg0: tensor<3> = [x, y, z]
  arg1: tensor<3xM> = [
      [_, _, ..., _, _],
      [_, _, ..., _, _],
      [_, _, ..., _, _],
  ]

  is treated as

  arg0: tensor<1x3> = [
      [x, y, z]
  ]
  arg1: tensor<3xM> = [
      [_, _, ..., _, _],
      [_, _, ..., _, _],
      [_, _, ..., _, _],
  ]

  and matrix multiplication is performed with the following form (1x3 @ 3xM -> 1xM)

  result: tensor<1xM> = [[_, _, ..., _, _]]

  finally, the first dimension is removed by definition so the result has the following form

  result: tensor<M>  = [_, _, ..., _, _]

- If the second argument is 1-D,
  it is treated as a matrix with a single column and standard matrix multiplication is performed.

  After standard matrix multiplication,
  the last dimension is removed from the result.

  e.g.,

  arg0: tensor<Mx3> = [
      [_, _, _],
      [_, _, _],
      ...,
      [_, _, _],
      [_, _, _],
  ]
  arg1: tensor<3> = [x, y, z]

  is treated as

  arg0: tensor<Mx3> = [
      [_, _, _],
      [_, _, _],
      ...,
      [_, _, _],
      [_, _, _],
  ]
  arg1: tensor<3x1> = [
    [x],
    [y],
    [z],
  ]

  and matrix multiplication is performed with the following form (Mx3 @ 3x1 -> Mx1)

  result: tensor<Mx1> = [
    [_],
    [_],
      ...,
    [_],
    [_],
  ]

  finally, the last dimension is removed by definition so the result has the following form

  result: tensor<M> = [_, _, _]

- If either argument is N-D where N > 2,
  the operation is treated as a collection of matrices residing in the last two indices and broadcasted accordingly.

  arg0: tensor<Kx1MxN> = [...]
  arg1: tensor<LxNxP> = [...]

  result: tensor<KxLxMxP> = [...]
```

```mlir
"FHELinalg.matmul_eint_eint(%a, %b) : (tensor<MxNx!FHE.eint<p>>, tensor<NxPx!FHE.eint<p>'>) -> tensor<MxPx!FHE.eint<p>>"
"FHELinalg.matmul_eint_eint(%a, %b) : (tensor<KxLxMxNx!FHE.eint<p>>, tensor<KxLxNxPx!FHE.eint<p>'>) -> tensor<KxLxMxPx!FHE.eint<p>>"
"FHELinalg.matmul_eint_eint(%a, %b) : (tensor<MxNx!FHE.eint<p>>, tensor<Nx!FHE.eint<p>'>) -> tensor<Mx!FHE.eint<p>>"
"FHELinalg.matmul_eint_eint(%a, %b) : (tensor<Nx!FHE.eint<p>>, tensor<NxPx!FHE.eint<p>'>) -> tensor<Px!FHE.eint<p>>"
```

Examples:

```mlir
// Returns the matrix multiplication of a 3x2 matrix of encrypted integers and a 2x3 matrix of integers.
//         [ 1, 2, 3]
//         [ 2, 3, 4]
//       *
// [1,2]   [ 5, 8,11]
// [3,4] = [11,18,25]
// [5,6]   [17,28,39]
//
"FHELinalg.matmul_eint_eint"(%a, %b) : (tensor<3x2x!FHE.eint<6>>, tensor<2x3x!FHE.eint<6>>) -> tensor<3x3x!FHE.eint<12>>
```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEint

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.matmul_eint_int` (::mlir::concretelang::FHELinalg::MatMulEintIntOp)

Returns a tensor that contains the result of the matrix multiplication of a matrix of encrypted integers and a matrix of clear integers.

Performs a matrix multiplication of a matrix of encrypted integers and a matrix of clear integers. The width of the clear integers must be less than or equal to the width of encrypted integers.

The behavior depends on the arguments in the following way:

```
- If both arguments are 2-D,
  they are multiplied like conventional matrices.

  e.g.,

  arg0: tensor<MxN> = [...]
  arg1: tensor<NxP> = [...]

  result: tensor<MxP> = [...]

- If the first argument is a vector (1-D),
  it is treated as a matrix with a single row and standard matrix multiplication is performed.

  After standard matrix multiplication,
  the first dimension is removed from the result.

  e.g.,

  arg0: tensor<3> = [x, y, z]
  arg1: tensor<3xM> = [
      [_, _, ..., _, _],
      [_, _, ..., _, _],
      [_, _, ..., _, _],
  ]

  is treated as

  arg0: tensor<1x3> = [
      [x, y, z]
  ]
  arg1: tensor<3xM> = [
      [_, _, ..., _, _],
      [_, _, ..., _, _],
      [_, _, ..., _, _],
  ]

  and matrix multiplication is performed with the following form (1x3 @ 3xM -> 1xM)

  result: tensor<1xM> = [[_, _, ..., _, _]]

  finally, the first dimension is removed by definition so the result has the following form

  result: tensor<M>  = [_, _, ..., _, _]

- If the second argument is 1-D,
  it is treated as a matrix with a single column and standard matrix multiplication is performed.

  After standard matrix multiplication,
  the last dimension is removed from the result.

  e.g.,

  arg0: tensor<Mx3> = [
      [_, _, _],
      [_, _, _],
      ...,
      [_, _, _],
      [_, _, _],
  ]
  arg1: tensor<3> = [x, y, z]

  is treated as

  arg0: tensor<Mx3> = [
      [_, _, _],
      [_, _, _],
      ...,
      [_, _, _],
      [_, _, _],
  ]
  arg1: tensor<3x1> = [
    [x],
    [y],
    [z],
  ]

  and matrix multiplication is performed with the following form (Mx3 @ 3x1 -> Mx1)

  result: tensor<Mx1> = [
    [_],
    [_],
      ...,
    [_],
    [_],
  ]

  finally, the last dimension is removed by definition so the result has the following form

  result: tensor<M> = [_, _, _]

- If either argument is N-D where N > 2,
  the operation is treated as a collection of matrices residing in the last two indices and broadcasted accordingly.

  arg0: tensor<Kx1MxN> = [...]
  arg1: tensor<LxNxP> = [...]

  result: tensor<KxLxMxP> = [...]
```

```mlir
"FHELinalg.matmul_eint_int(%a, %b) : (tensor<MxNx!FHE.eint<p>>, tensor<NxPxip'>) -> tensor<MxPx!FHE.eint<p>>"
"FHELinalg.matmul_eint_int(%a, %b) : (tensor<KxLxMxNx!FHE.eint<p>>, tensor<KxLxNxPxip'>) -> tensor<KxLxMxPx!FHE.eint<p>>"
"FHELinalg.matmul_eint_int(%a, %b) : (tensor<MxNx!FHE.eint<p>>, tensor<Nxip'>) -> tensor<Mx!FHE.eint<p>>"
"FHELinalg.matmul_eint_int(%a, %b) : (tensor<Nx!FHE.eint<p>>, tensor<NxPxip'>) -> tensor<Px!FHE.eint<p>>"
```

Examples:

```mlir
// Returns the matrix multiplication of a 3x2 matrix of encrypted integers and a 2x3 matrix of integers.
//         [ 1, 2, 3]
//         [ 2, 3, 4]
//       *
// [1,2]   [ 5, 8,11]
// [3,4] = [11,18,25]
// [5,6]   [17,28,39]
//
"FHELinalg.matmul_eint_int"(%a, %b) : (tensor<3x2x!FHE.eint<6>>, tensor<2x3xi7>) -> tensor<3x3x!FHE.eint<6>>
```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEintInt

Interfaces: Binary, BinaryEintInt, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.matmul_int_eint` (::mlir::concretelang::FHELinalg::MatMulIntEintOp)

Returns a tensor that contains the result of the matrix multiplication of a matrix of clear integers and a matrix of encrypted integers.

Performs a matrix multiplication of a matrix of clear integers and a matrix of encrypted integers. The width of the clear integers must be less than or equal to the width of encrypted integers.

The behavior depends on the arguments in the following way:

```
- If both arguments are 2-D,
  they are multiplied like conventional matrices.

  e.g.,

  arg0: tensor<MxN> = [...]
  arg1: tensor<NxP> = [...]

  result: tensor<MxP> = [...]

- If the first argument is a vector (1-D),
  it is treated as a matrix with a single row and standard matrix multiplication is performed.

  After standard matrix multiplication,
  the first dimension is removed from the result.

  e.g.,

  arg0: tensor<3> = [x, y, z]
  arg1: tensor<3xM> = [
      [_, _, ..., _, _],
      [_, _, ..., _, _],
      [_, _, ..., _, _],
  ]

  is treated as

  arg0: tensor<1x3> = [
      [x, y, z]
  ]
  arg1: tensor<3xM> = [
      [_, _, ..., _, _],
      [_, _, ..., _, _],
      [_, _, ..., _, _],
  ]

  and matrix multiplication is performed with the following form (1x3 @ 3xM -> 1xM)

  result: tensor<1xM> = [[_, _, ..., _, _]]

  finally, the first dimension is removed by definition so the result has the following form

  result: tensor<M>  = [_, _, ..., _, _]

- If the second argument is 1-D,
  it is treated as a matrix with a single column and standard matrix multiplication is performed.

  After standard matrix multiplication,
  the last dimension is removed from the result.

  e.g.,

  arg0: tensor<Mx3> = [
      [_, _, _],
      [_, _, _],
      ...,
      [_, _, _],
      [_, _, _],
  ]
  arg1: tensor<3> = [x, y, z]

  is treated as

  arg0: tensor<Mx3> = [
      [_, _, _],
      [_, _, _],
      ...,
      [_, _, _],
      [_, _, _],
  ]
  arg1: tensor<3x1> = [
    [x],
    [y],
    [z],
  ]

  and matrix multiplication is performed with the following form (Mx3 @ 3x1 -> Mx1)

  result: tensor<Mx1> = [
    [_],
    [_],
      ...,
    [_],
    [_],
  ]

  finally, the last dimension is removed by definition so the result has the following form

  result: tensor<M> = [_, _, _]

- If either argument is N-D where N > 2,
  the operation is treated as a collection of matrices residing in the last two indices and broadcasted accordingly.

  arg0: tensor<Kx1MxN> = [...]
  arg1: tensor<LxNxP> = [...]

  result: tensor<KxLxMxP> = [...]
```

```mlir
"FHELinalg.matmul_int_eint(%a, %b) : (tensor<MxNxip'>, tensor<NxPxFHE.eint<p>>) -> tensor<MxPx!FHE.eint<p>>"
"FHELinalg.matmul_int_eint(%a, %b) : (tensor<KxLxMxNxip'>, tensor<KxLxNxPxFHE.eint<p>>) -> tensor<KxLxMxPx!FHE.eint<p>>"
"FHELinalg.matmul_int_eint(%a, %b) : (tensor<MxNxip'>, tensor<NxFHE.eint<p>>) -> tensor<Mx!FHE.eint<p>>"
"FHELinalg.matmul_int_eint(%a, %b) : (tensor<Nxip'>, tensor<NxPxFHE.eint<p>>) -> tensor<Px!FHE.eint<p>>"
```

Examples:

```mlir
// Returns the matrix multiplication of a 3x2 matrix of clear integers and a 2x3 matrix of encrypted integers.
//         [ 1, 2, 3]
//         [ 2, 3, 4]
//       *
// [1,2]   [ 5, 8,11]
// [3,4] = [11,18,25]
// [5,6]   [17,28,39]
//
"FHELinalg.matmul_int_eint"(%a, %b) : (tensor<3x2xi7>, tensor<2x3x!FHE.eint<6>>) -> tensor<3x3x!FHE.eint<6>>
```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryIntEint

Interfaces: Binary, BinaryIntEint, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.maxpool2d` (::mlir::concretelang::FHELinalg::Maxpool2dOp)

Returns the 2D maxpool of a tensor in the form NCHW

Interfaces: UnaryEint

#### Attributes:

|    Attribute   |           MLIR Type          | Description                                |
| :------------: | :--------------------------: | ------------------------------------------ |
| `kernel_shape` | ::mlir::DenseIntElementsAttr | 64-bit signless integer elements attribute |
|    `strides`   | ::mlir::DenseIntElementsAttr | 64-bit signless integer elements attribute |
|   `dilations`  | ::mlir::DenseIntElementsAttr | 64-bit signless integer elements attribute |

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.mul_eint_int` (::mlir::concretelang::FHELinalg::MulEintIntOp)

Returns a tensor that contains the multiplication of a tensor of encrypted integers and a tensor of clear integers.

Performs a multiplication following the broadcasting rules between a tensor of encrypted integers and a tensor of clear integers. The width of the clear integers must be less than or equal to the width of encrypted integers.

Examples:

```mlir
// Returns the term-by-term multiplication of `%a0` with `%a1`
"FHELinalg.mul_eint_int"(%a0, %a1) : (tensor<4x!FHE.eint<4>>, tensor<4xi5>) -> tensor<4x!FHE.eint<4>>

// Returns the term-by-term multiplication of `%a0` with `%a1`, where dimensions equal to one are stretched.
"FHELinalg.mul_eint_int"(%a0, %a1) : (tensor<4x1x4x!FHE.eint<4>>, tensor<1x4x4xi5>) -> tensor<4x4x4x!FHE.eint<4>>

// Returns the multiplication of a 3x3 matrix of encrypted integers and a 3x1 matrix (a column) of integers.
//
// [1,2,3]   [1]   [1,2,3]
// [4,5,6] * [2] = [8,10,18]
// [7,8,9]   [3]   [21,24,27]
//
// The dimension #1 of operand #2 is stretched as it is equal to 1.
"FHELinalg.mul_eint_int"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<3x1xi5>) -> tensor<3x3x!FHE.eint<4>>

// Returns the multiplication of a 3x3 matrix of encrypted integers and a 1x3 matrix (a line) of integers.
//
// [1,2,3]             [2,4,6]
// [4,5,6] * [1,2,3] = [5,7,9]
// [7,8,9]             [8,10,12]
//
// The dimension #2 of operand #2 is stretched as it is equal to 1.
"FHELinalg.mul_eint_int"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<1x3xi5>) -> tensor<3x3x!FHE.eint<4>>

// Same behavior as the previous one, but as the dimension #2 is missing of operand #2.
"FHELinalg.mul_eint_int"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<3xi5>) -> tensor<3x3x!FHE.eint<4>>

```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEintInt, TensorBroadcastingRules

Interfaces: Binary, BinaryEintInt, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.mul_eint` (::mlir::concretelang::FHELinalg::MulEintOp)

Returns a tensor that contains the multiplication of two tensor of encrypted integers.

Performs an addition following the broadcasting rules between two tensors of encrypted integers. The width of the encrypted integers must be equal.

Examples:

```mlir
// Returns the term-by-term multiplication of `%a0` with `%a1`
"FHELinalg.mul_eint"(%a0, %a1) : (tensor<4x!FHE.eint<8>>, tensor<4x!FHE.eint<8>>) -> tensor<4x!FHE.eint<8>>

// Returns the term-by-term multiplication of `%a0` with `%a1`, where dimensions equal to one are stretched.
"FHELinalg.mul_eint"(%a0, %a1) : (tensor<4x1x4x!FHE.eint<8>>, tensor<1x4x4x!FHE.eint<8>>) -> tensor<4x4x4x!FHE.eint<8>>

// Returns the multiplication of a 3x3 matrix of encrypted integers and a 3x1 matrix (a column) of encrypted integers.
//
// [1,2,3]   [1]   [1,2,3]
// [4,5,6] * [2] = [8,10,12]
// [7,8,9]   [3]   [21,24,27]
//
// The dimension #1 of operand #2 is stretched as it is equal to 1.
"FHELinalg.mul_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<8>>, tensor<3x1x!FHE.eint<8>>) -> tensor<3x3x!FHE.eint<8>>

// Returns the multiplication of a 3x3 matrix of encrypted integers and a 1x3 matrix (a line) of encrypted integers.
//
// [1,2,3]             [1,4,9]
// [4,5,6] * [1,2,3] = [4,10,18]
// [7,8,9]             [7,16,27]
//
// The dimension #2 of operand #2 is stretched as it is equal to 1.
"FHELinalg.mul_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<8>>, tensor<1x3x!FHE.eint<8>>) -> tensor<3x3x!FHE.eint<8>>

// Same behavior as the previous one, but as the dimension #2 of operand #2 is missing.
"FHELinalg.mul_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<8>>, tensor<3x!FHE.eint<8>>) -> tensor<3x3x!FHE.eint<8>>
```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEint, TensorBroadcastingRules

Interfaces: BinaryEint, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.neg_eint` (::mlir::concretelang::FHELinalg::NegEintOp)

Returns a tensor that contains the negation of a tensor of encrypted integers.

Performs a negation to a tensor of encrypted integers.

Examples:

```mlir
// Returns the term-by-term negation of `%a0`
"FHELinalg.neg_eint"(%a0) : (tensor<3x3x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>
//
//        ( [1,2,3] )   [31,30,29]
// negate ( [4,5,6] ) = [28,27,26]
//        ( [7,8,9] )   [25,24,23]
//
// The negation is computed as `2**(p+1) - a` where p=4 here.
```

Traits: AlwaysSpeculatableImplTrait, TensorUnaryEint

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnaryEint

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.reinterpret_precision` (::mlir::concretelang::FHELinalg::ReinterpretPrecisionEintOp)

Reinterpret the ciphertext tensor with a different precision.

It's a reinterpretation cast which changes only the precision. On CRT represention, it does nothing. On Native representation, it moves the message/noise further forward, effectively changing the precision. Changing to - a bigger precision is safe, as the crypto-parameters are chosen such that only zeros will come from the noise part. This is equivalent to a shift left for the value - a smaller precision is only safe if you clear the lowest message bits first. If not, you can assume small errors with high probability and frequent bigger errors, which can be contained to small errors using margins. This is equivalent to a shift right for the value

Example:

```mlir
 // assuming a is encoded as 4bits but can be stored in 2bits
 // we can obtain a to a smaller 2 bits precision
 %shifted_a = "FHELinalg.mul_eint_intlsb"(%a, %c_4): (tensor<1x!FHE.eint<4>>) -> (tensor<1x!FHE.eint<2>>)
 %a_small_precision = "FHELinalg.reinterpret_precision"(%shifted_a, %lsb) : (tensor<1x!FHE.eint<4>>) -> (tensor<1x!FHE.eint<2>>)
```

Traits: AlwaysSpeculatableImplTrait, TensorUnaryEint

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnaryEint

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` |             |

#### Results:

|  Result  | Description |
| :------: | ----------- |
| `output` |             |

### `FHELinalg.round` (::mlir::concretelang::FHELinalg::RoundOp)

Rounds a tensor of ciphertexts into a smaller precision.

````
  Assuming a ciphertext whose message is implemented over `p` bits, this
  operation rounds it to fit to `q` bits where `p>q`.

  Example:
  ```mlir
  // ok
  "FHELinalg.round"(%a): (tensor<3x!FHE.eint<6>>) -> (tensor<3x!FHE.eint<5>>)
  "FHELinalg.round"(%a): (tensor<3x!FHE.eint<5>>) -> (tensor<3x!FHE.eint<3>>)
  "FHELinalg.round"(%a): (tensor<3x!FHE.eint<3>>) -> (tensor<3x!FHE.eint<2>>)
  "FHELinalg.round"(%a): (tensor<3x!FHE.esint<3>>) -> (tensor<3x!FHE.esint<2>>)

  // error
  "FHELinalg.round"(%a): (tensor<3x!FHE.eint<6>>) -> (tensor<3x!FHE.eint<6>>)
  "FHELinalg.round"(%a): (tensor<3x!FHE.eint<4>>) -> (tensor<3x!FHE.eint<5>>)
  "FHELinalg.round"(%a): (tensor<3x!FHE.eint<4>>) -> (tensor<3x!FHE.esint<2>>)
````

````

Traits: AlwaysSpeculatableImplTrait, TensorUnaryEint

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnaryEint

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` | 

#### Results:

| Result | Description |
| :----: | ----------- |
| `output` | 

### `FHELinalg.sub_eint_int` (::mlir::concretelang::FHELinalg::SubEintIntOp)

Returns a tensor that contains the subtraction of a tensor of clear integers from a tensor of encrypted integers.

Performs a subtraction following the broadcasting rules between a tensor of clear integers from a tensor of encrypted integers.
The width of the clear integers must be less than or equal to the width of encrypted integers.

Examples:
```mlir
// Returns the term-by-term subtraction of `%a0` with `%a1`
"FHELinalg.sub_eint_int"(%a0, %a1) : (tensor<4x!FHE.eint<4>>, tensor<4xi5>) -> tensor<4x!FHE.eint<4>>

// Returns the term-by-term subtraction of `%a0` with `%a1`, where dimensions equal to one are stretched.
"FHELinalg.sub_eint_int"(%a0, %a1) : (tensor<1x4x4x!FHE.eint<4>>, tensor<4x1x4xi5>) -> tensor<4x4x4x!FHE.eint<4>>

// Returns the subtraction of a 3x3 matrix of integers and a 3x1 matrix (a column) of encrypted integers.
//
// [1,2,3]   [1]   [0,2,3]
// [4,5,6] - [2] = [2,3,4]
// [7,8,9]   [3]   [4,5,6]
//
// The dimension #1 of operand #2 is stretched as it is equal to 1.
"FHELinalg.sub_eint_int"(%a0, %a1) : (tensor<3x1x!FHE.eint<4>>, tensor<3x3xi5>) -> tensor<3x3x!FHE.eint<4>>

// Returns the subtraction of a 3x3 matrix of integers and a 1x3 matrix (a line) of encrypted integers.
//
// [1,2,3]             [0,0,0]
// [4,5,6] - [1,2,3] = [3,3,3]
// [7,8,9]             [6,6,6]
//
// The dimension #2 of operand #2 is stretched as it is equal to 1.
"FHELinalg.sub_eint_int"(%a0, %a1) : (tensor<1x3x!FHE.eint<4>>, tensor<3x3xi5>) -> tensor<3x3x!FHE.eint<4>>

// Same behavior as the previous one, but as the dimension #2 is missing of operand #2.
"FHELinalg.sub_eint_int"(%a0, %a1) : (tensor<3x!FHE.eint<4>>, tensor<3x3xi5>) -> tensor<3x3x!FHE.eint<4>>

````

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEintInt, TensorBroadcastingRules

Interfaces: Binary, BinaryEintInt, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.sub_eint` (::mlir::concretelang::FHELinalg::SubEintOp)

Returns a tensor that contains the subtraction of two tensor of encrypted integers.

Performs an subtraction following the broadcasting rules between two tensors of encrypted integers. The width of the encrypted integers must be equal.

Examples:

```mlir
// Returns the term-by-term subtraction of `%a0` with `%a1`
"FHELinalg.sub_eint"(%a0, %a1) : (tensor<4x!FHE.eint<4>>, tensor<4x!FHE.eint<4>>) -> tensor<4x!FHE.eint<4>>

// Returns the term-by-term subtraction of `%a0` with `%a1`, where dimensions equal to one are stretched.
"FHELinalg.sub_eint"(%a0, %a1) : (tensor<4x1x4x!FHE.eint<4>>, tensor<1x4x4x!FHE.eint<4>>) -> tensor<4x4x4x!FHE.eint<4>>

// Returns the subtraction of a 3x3 matrix of integers and a 3x1 matrix (a column) of encrypted integers.
//
// [1,2,3]   [1]   [0,2,3]
// [4,5,6] - [2] = [2,3,4]
// [7,8,9]   [3]   [4,5,6]
//
// The dimension #1 of operand #2 is stretched as it is equal to 1.
"FHELinalg.sub_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<3x1x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>

// Returns the subtraction of a 3x3 matrix of integers and a 1x3 matrix (a line) of encrypted integers.
//
// [1,2,3]             [0,0,0]
// [4,5,6] - [1,2,3] = [3,3,3]
// [7,8,9]             [6,6,6]
//
// The dimension #2 of operand #2 is stretched as it is equal to 1.
"FHELinalg.sub_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<1x3x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>

// Same behavior as the previous one, but as the dimension #2 of operand #2 is missing.
"FHELinalg.sub_eint"(%a0, %a1) : (tensor<3x3x!FHE.eint<4>>, tensor<3x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>
```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryEint, TensorBroadcastingRules

Interfaces: BinaryEint, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.sub_int_eint` (::mlir::concretelang::FHELinalg::SubIntEintOp)

Returns a tensor that contains the subtraction of a tensor of clear integers and a tensor of encrypted integers.

Performs a subtraction following the broadcasting rules between a tensor of clear integers and a tensor of encrypted integers. The width of the clear integers must be less than or equal to the width of encrypted integers.

Examples:

```mlir
// Returns the term-by-term subtraction of `%a0` with `%a1`
"FHELinalg.sub_int_eint"(%a0, %a1) : (tensor<4xi5>, tensor<4x!FHE.eint<4>>) -> tensor<4x!FHE.eint<4>>

// Returns the term-by-term subtraction of `%a0` with `%a1`, where dimensions equal to one are stretched.
"FHELinalg.sub_int_eint"(%a0, %a1) : (tensor<4x1x4xi5>, tensor<1x4x4x!FHE.eint<4>>) -> tensor<4x4x4x!FHE.eint<4>>

// Returns the subtraction of a 3x3 matrix of integers and a 3x1 matrix (a column) of encrypted integers.
//
// [1,2,3]   [1]   [0,2,3]
// [4,5,6] - [2] = [2,3,4]
// [7,8,9]   [3]   [4,5,6]
//
// The dimension #1 of operand #2 is stretched as it is equal to 1.
"FHELinalg.sub_int_eint"(%a0, %a1) : (tensor<3x3xi5>, tensor<3x1x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>

// Returns the subtraction of a 3x3 matrix of integers and a 1x3 matrix (a line) of encrypted integers.
//
// [1,2,3]             [0,0,0]
// [4,5,6] - [1,2,3] = [3,3,3]
// [7,8,9]             [6,6,6]
//
// The dimension #2 of operand #2 is stretched as it is equal to 1.
"FHELinalg.sub_int_eint"(%a0, %a1) : (tensor<3x3xi5>, tensor<1x3x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>

// Same behavior as the previous one, but as the dimension #2 is missing of operand #2.
"FHELinalg.sub_int_eint"(%a0, %a1) : (tensor<3x3xi5>, tensor<3x!FHE.eint<4>>) -> tensor<3x3x!FHE.eint<4>>

```

Traits: AlwaysSpeculatableImplTrait, TensorBinaryIntEint, TensorBroadcastingRules

Interfaces: Binary, BinaryIntEint, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
|  `lhs`  |             |
|  `rhs`  |             |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» |             |

### `FHELinalg.sum` (::mlir::concretelang::FHELinalg::SumOp)

Returns the sum of elements of a tensor of encrypted integers along specified axes.

Attributes:

* keep\_dims: boolean = false whether to keep the rank of the tensor after the sum operation if true, reduced axes will have the size of 1
* axes: I64ArrayAttr = \[] list of dimension to perform the sum along think of it as the dimensions to reduce (see examples below to get an intuition)

Examples:

```mlir
// Returns the sum of all elements of `%a0`
"FHELinalg.sum"(%a0) : (tensor<3x3x!FHE.eint<4>>) -> !FHE.eint<4>
//
//     ( [1,2,3] )
// sum ( [4,5,6] ) = 45
//     ( [7,8,9] )
//
```

```mlir
// Returns the sum of all elements of `%a0` along columns
"FHELinalg.sum"(%a0) { axes = [0] } : (tensor<3x2x!FHE.eint<4>>) -> tensor<2x!FHE.eint<4>>
//
//     ( [1,2] )
// sum ( [3,4] ) = [9, 12]
//     ( [5,6] )
//
```

```mlir
// Returns the sum of all elements of `%a0` along columns while preserving dimensions
"FHELinalg.sum"(%a0) { axes = [0], keep_dims = true } : (tensor<3x2x!FHE.eint<4>>) -> tensor<1x2x!FHE.eint<4>>
//
//     ( [1,2] )
// sum ( [3,4] ) = [[9, 12]]
//     ( [5,6] )
//
```

```mlir
// Returns the sum of all elements of `%a0` along rows
"FHELinalg.sum"(%a0) { axes = [1] } : (tensor<3x2x!FHE.eint<4>>) -> tensor<3x!FHE.eint<4>>
//
//     ( [1,2] )
// sum ( [3,4] ) = [3, 7, 11]
//     ( [5,6] )
//
```

```mlir
// Returns the sum of all elements of `%a0` along rows while preserving dimensions
"FHELinalg.sum"(%a0) { axes = [1], keep_dims = true } : (tensor<3x2x!FHE.eint<4>>) -> tensor<3x1x!FHE.eint<4>>
//
//     ( [1,2] )   [3]
// sum ( [3,4] ) = [7]
//     ( [5,6] )   [11]
//
```

Traits: AlwaysSpeculatableImplTrait, TensorUnaryEint

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

#### Attributes:

|  Attribute  |     MLIR Type     | Description                    |
| :---------: | :---------------: | ------------------------------ |
|    `axes`   | ::mlir::ArrayAttr | 64-bit integer array attribute |
| `keep_dims` |  ::mlir::BoolAttr | bool attribute                 |

#### Operands:

|  Operand | Description |
| :------: | ----------- |
| `tensor` |             |

#### Results:

| Result | Description |
| :----: | ----------- |
|  `out` |             |

### `FHELinalg.to_signed` (::mlir::concretelang::FHELinalg::ToSignedOp)

Cast an unsigned integer tensor to a signed one

Cast an unsigned integer tensor to a signed one. The result must have the same width and the same shape as the input.

The behavior is undefined on overflow/underflow.

Examples:

```mlir
// ok
"FHELinalg.to_signed"(%x) : (tensor<3x2x!FHE.eint<2>>) -> tensor<3x2x!FHE.esint<2>>

// error
"FHELinalg.to_signed"(%x) : (tensor<3x2x!FHE.eint<2>>) -> tensor<3x2x!FHE.esint<3>>
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnaryEint

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` |             |

#### Results:

|  Result  | Description |
| :------: | ----------- |
| `output` |             |

### `FHELinalg.to_unsigned` (::mlir::concretelang::FHELinalg::ToUnsignedOp)

Cast a signed integer tensor to an unsigned one

Cast a signed integer tensor to an unsigned one. The result must have the same width and the same shape as the input.

The behavior is undefined on overflow/underflow.

Examples:

```mlir
// ok
"FHELinalg.to_unsigned"(%x) : (tensor<3x2x!FHE.esint<2>>) -> tensor<3x2x!FHE.eint<2>>

// error
"FHELinalg.to_unsigned"(%x) : (tensor<3x2x!FHE.esint<2>>) -> tensor<3x2x!FHE.eint<3>>
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnaryEint

Effects: MemoryEffects::Effect{}

#### Operands:

| Operand | Description |
| :-----: | ----------- |
| `input` |             |

#### Results:

|  Result  | Description |
| :------: | ----------- |
| `output` |             |

### `FHELinalg.transpose` (::mlir::concretelang::FHELinalg::TransposeOp)

Returns a tensor that contains the transposition of the input tensor.

Performs a transpose operation on an N-dimensional tensor.

Attributes:

* axes: I64ArrayAttr = \[] list of dimension to perform the transposition contains a permutation of \[0,1,..,N-1] where N is the number of axes think of it as a way to rearrange axes (see the example below)

```mlir
"FHELinalg.transpose"(%a) : (tensor<n0xn1x...xnNxType>) -> tensor<nNx...xn1xn0xType>
```

Examples:

```mlir
// Transpose the input tensor
// [1,2]    [1, 3, 5]
// [3,4] => [2, 4, 6]
// [5,6]
//
"FHELinalg.transpose"(%a) : (tensor<3x2xi7>) -> tensor<2x3xi7>
```

```mlir
"FHELinalg.transpose"(%a) { axes = [1, 3, 0, 2] } : (tensor<2x3x4x5xi7>) -> tensor<3x5x2x4xi7>
```

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), UnaryEint

Effects: MemoryEffects::Effect{}

#### Attributes:

| Attribute |     MLIR Type     | Description                    |
| :-------: | :---------------: | ------------------------------ |
|   `axes`  | ::mlir::ArrayAttr | 64-bit integer array attribute |

#### Operands:

|  Operand | Description |
| :------: | ----------- |
| `tensor` | any type    |

#### Results:

|   Result  | Description |
| :-------: | ----------- |
| «unnamed» | any type    |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.zama.org/concrete/2.7-1/developers/dialects/fhelinalgdialect.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
