> ## Documentation Index
> Fetch the complete documentation index at: https://docs.classiq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Composing and Transforming Block Encodings

Once you have one or more `BlockEncoding` instances (see
[Constructing Block Encodings](/user-guide/applications/block-encoding/constructing-block-encodings)),
combine them with arithmetic operators or classmethods to block-encode sums, products, and scaled
matrices, or transform a single encoding into its inverse or its qubitized walk operator. This
page covers a selection of the available combinators and transformations — more are added over
time, so check the [SDK reference](/sdk-reference/applications/block_encoding) for the full,
current list. Every combinator returns a new
`BlockEncoding` with `alpha`, `block_size`, and `hermitian_be` computed from its inputs.

All examples on this page import:

```python theme={null}
from classiq.applications.block_encoding import BlockEncoding
```

## Sum: `+`

`be_a + be_b` block-encodes $A + B$ via LCU, using one extra block qubit to select between the
two branches.

```python theme={null}
from classiq.applications.block_encoding import BlockEncoding

diag_a = [2, 7, 1, 5]
diag_b = [4, 1, 6, 3]
be_a = BlockEncoding.from_dense_diagonals([(diag_a, 0)])
be_b = BlockEncoding.from_dense_diagonals([(diag_b, 0)])

be_sum = be_a + be_b
print(be_sum.alpha)  # 13.0 == be_a.alpha + be_b.alpha
print(be_sum.to_matrix().round(3))
```

`be_sum.alpha` prints `13.0`, and `be_sum.to_matrix()` is the diagonal matrix $\text{diag}(6, 8, 7, 8)$.

## Weighted sum: `weighted_sum`

For more than two terms, or complex coefficients, use `BlockEncoding.weighted_sum` directly
instead of chaining `+`: it's more efficient.

```python theme={null}
from classiq.applications.block_encoding import BlockEncoding

diag_a = [2, 7, 1, 5]
diag_b = [4, 1, 6, 3]
be_a = BlockEncoding.from_dense_diagonals([(diag_a, 0)])
be_b = BlockEncoding.from_dense_diagonals([(diag_b, 0)])

be_ws = BlockEncoding.weighted_sum([2, 3], [be_a, be_b])
print(be_ws.alpha)  # 2*7 + 3*6 = 32.0
print(be_ws.to_matrix().round(3))
```

`be_ws.alpha` prints `32.0`, and `be_ws.to_matrix()` is the diagonal matrix $\text{diag}(16, 17, 20, 19)$.

## Scalar multiplication: `*` / `rmul`

`scalar * be` (or `be * scalar`) block-encodes $c \cdot A$ for a complex scalar $c$. `block_size`
is unchanged; `alpha` is rescaled by $\vert c \vert$.

```python theme={null}
from classiq.applications.block_encoding import BlockEncoding

diag_values = [3, 7, 2, 5]
be = BlockEncoding.from_dense_diagonals([(diag_values, 0)])
be_scaled = 2.0 * be
print(be_scaled.alpha)  # 14.0 == 2.0 * 7.0
print(be_scaled.to_matrix().round(3))
```

`be_scaled.alpha` prints `14.0`, and `be_scaled.to_matrix()` is the diagonal matrix
$\text{diag}(6, 14, 4, 10)$.

## Product: `@` / `product`

`be_a @ be_b` block-encodes the product $A \cdot B$, applying `be_b`'s unitary followed by
`be_a`'s. `BlockEncoding.product([be_1, ..., be_n])` generalizes this to more than two factors
efficiently.

```python theme={null}
from classiq.applications.block_encoding import BlockEncoding

diag_a = [2, 5]
diag_b = [3, 1]
diag_c = [0.7, 2.2]
be_product = BlockEncoding.product(
    [
        BlockEncoding.from_dense_diagonals([(diag_a, 0)]),
        BlockEncoding.from_dense_diagonals([(diag_b, 0)]),
        BlockEncoding.from_dense_diagonals([(diag_c, 0)]),
    ]
)
print(be_product.alpha)  # 5 * 3 * 2.2 = 33.0
print(be_product.to_matrix().round(3))
```

`be_product.alpha` prints `33.0`, and `be_product.to_matrix()` is the diagonal matrix
$\text{diag}(4.2, 11)$.

## Inverse

`be.inverse(kappa)` block-encodes $A^{-1}$ using QSVT polynomial inversion, given an estimate
`kappa` of $A$'s condition number. Pass either the QSVT polynomial `degree`, or `eps` (a target
relative error, from which the degree is derived).

```python theme={null}
import numpy as np
from classiq.applications.block_encoding import BlockEncoding

matrix = np.array([[2.5, -1.5], [-1.5, 2.5]])
be = BlockEncoding.from_matrix(matrix).inverse(kappa=4, degree=201)
print(be.alpha)

actual = be.to_matrix()
expected = np.linalg.inv(matrix)

# Compare via fidelity rather than raw entries -- 1.0 confirms be correctly encodes the inverse:
fidelity = abs(np.vdot(expected, actual)) / (np.linalg.norm(expected) * np.linalg.norm(actual))
print(round(fidelity, 6))
```

```
6.936372350713854
1.0
```

See [Verifying with `to_matrix`](#to_matrix) for more on this global-phase caveat.

## Qubitize

`be.qubitize()` builds the Low–Chuang qubitization walk operator $W = R U$, where $R$
reflects about the block variable's $\vert 0 \rangle$ state and $U$ is `be`'s own unitary.
Powers of $W$ give Chebyshev polynomials of the encoded matrix:
$\langle 0 \vert W^k \vert 0 \rangle = T_k(A / \alpha)$. These are the basis of quantum signal
processing and QSVT algorithms.

`qubitize` requires `be.hermitian_be=True` and `be.block_size > 0`. The walk operator is built
from two reflections, so $U$ itself must also be Hermitian. It also needs a block variable to
reflect about.

<Note>
  `hermitian_be` is computed automatically by every constructor and combinator on this page and in
  [Constructing Block Encodings](/user-guide/applications/block-encoding/constructing-block-encodings).
  If you're confident your block encoding's unitary is Hermitian but the computed value is
  `False` (or vice versa), you can build a corrected copy with
  `dataclasses.replace(be, hermitian_be=True)`. Only do this when you're sure it's genuinely true
  — `qubitize`'s walk operator is only correct when `hermitian_be` reflects reality.
</Note>

## Verifying with `to_matrix`

`be.to_matrix()` reconstructs the encoded matrix $A$ by state-vector simulation: it prepares an
equal superposition over `data`, applies `be.unitary`, post-selects the block variable on
`|0>`, and rescales by `alpha`. It's meant for testing and small examples, not as part of a
production algorithm.

<Warning>
  The reconstruction is exact only up to a single, unknown global phase. For the moment,
  `to_matrix()` does not resolve this phase, so when comparing against a known matrix, compare dot
  products or magnitudes rather than raw entries, as the [inverse](#inverse) example does.
</Warning>
