Hello,
I’ve implemented a bitonic sort algorithm using concrete. I’m trying different comparison strategies to see which one would be the most efficient. However, all of the strategies return the same complexity. Following is my code:
# Helper function to compare and swap two elements
def compare_and_swap(a, b, direction):
c = (a > b) if direction == 1 else (a < b)
a_new = c * b + (1 - c) * a
b_new = c * a + (1 - c) * b
return a_new, b_new
# Helper function to perform the bitonic merge
def bitonic_merge(arr, low, cnt, direction):
if cnt > 1:
k = cnt // 2
for i in range(low, low + k):
arr[i], arr[i + k] = compare_and_swap(arr[i], arr[i + k], direction)
bitonic_merge(arr, low, k, direction)
bitonic_merge(arr, low + k, k, direction)
# Helper function to perform bitonic sort recursively
def bitonic_sort(arr, low, cnt, direction):
if cnt > 1:
k = cnt // 2
bitonic_sort(arr, low, k, 1) # Sort first half in ascending order
bitonic_sort(arr, low + k, k, 0) # Sort second half in descending order
bitonic_merge(arr, low, cnt, direction) # Merge both halves
return arr
@fhe.compiler({"array": "encrypted"})
def sort_array_bitonic(array):
array = bitonic_sort(array, 0, array.size, 1)
return array
strategies = [
None,
fhe.ComparisonStrategy.ONE_TLU_PROMOTED,
fhe.ComparisonStrategy.THREE_TLU_CASTED,
fhe.ComparisonStrategy.TWO_TLU_BIGGER_PROMOTED_SMALLER_CASTED,
fhe.ComparisonStrategy.TWO_TLU_BIGGER_CASTED_SMALLER_PROMOTED,
fhe.ComparisonStrategy.THREE_TLU_BIGGER_CLIPPED_SMALLER_CASTED,
fhe.ComparisonStrategy.TWO_TLU_BIGGER_CLIPPED_SMALLER_PROMOTED,
fhe.ComparisonStrategy.CHUNKED,
]
for strategy in strategies:
print("Runnig with strategy ", strategy)
bitonic_circuit = sort_array_bitonic.compile(inputset, comparison_strategy_preference=strategy)
enc_array = bitonic_circuit.encrypt(input_array)
enc_result = bitonic_circuit.run(enc_array)
dec_array = bitonic_circuit.decrypt(enc_result)
print("output ", dec_array)
print("complexity ", bitonic_circuit.complexity)
Could you please confirm if I’m implementing the strategies correctly? If so, am I missing something that would explain why there’s no difference in execution time or complexity? If not, then what would be the correct way to approach this?