The default strategy is the one that doesn't increase the input bit width, even if it's less optimal than the others. If you don't care about the input bit widths (e.g., if the inputs are only used in this operation), you should definitely change the default strategy.
Choosing the correct strategy can lead to big speedups. So if you are not sure which one to use, you can compile with different strategies and compare the complexity.
For example, the following code:
import numpy as np
from concrete import fhe
def f(x, y):
return x & y
inputset = fhe.inputset(fhe.uint3, fhe.uint4)
strategies = [
fhe.BitwiseStrategy.ONE_TLU_PROMOTED,
fhe.BitwiseStrategy.THREE_TLU_CASTED,
fhe.BitwiseStrategy.TWO_TLU_BIGGER_PROMOTED_SMALLER_CASTED,
fhe.BitwiseStrategy.TWO_TLU_BIGGER_CASTED_SMALLER_PROMOTED,
fhe.BitwiseStrategy.CHUNKED,
]
for strategy in strategies:
compiler = fhe.Compiler(f, {"x": "encrypted", "y": "encrypted"})
circuit = compiler.compile(inputset, bitwise_strategy_preference=strategy)
print(
f"{strategy:>55} "
f"-> {circuit.programmable_bootstrap_count:>2} TLUs "
f"-> {int(circuit.complexity):>12_} complexity"
)
As you can see, strategies can affect the performance a lot! So make sure to select the appropriate one for your use case if you want to optimize performance.