Chaining compiled functions

(originally asked by VReyes on fhe.org discord)

Hello,

is it possible to ‘extract’ intermediate values in concrete-numpy? I have attempted compiling several functions and then saving the output of the first one, before feeding it into the second one. This fails, however, as these intermediate values are not of type PublicArguments as expected by the ‘run’ method of a compiled function. Is there a way to wrap the output of one circuit as PublicArguments to be fed into another circuit?

import concrete.numpy as cnp

@cnp.compiler({"a": "encrypted", "b": "encrypted"})
def add(a, b):
    return a + b

@cnp.compiler({"a": "encrypted"})
def mul(a):
    return a * 2

add_inputset = [(1,2), (3, 4)]
add_circuit = add.compile(add_inputset)

mul_inputset = [3, 7]
mul_circuit = mul.compile(mul_inputset)

add_args = add_circuit.encrypt(1, 2)
added = add_circuit.run(add_args)
multiplied = mul_circuit.run(added)
res = mul_circuit.decrypt(multiplied)
print(res)

This is a minimal example. I get the following error and stack trace. I aim to both relay added and multiply back to the client.

Traceback (most recent call last):
  File "/usr/lib/python3.10/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "pydev/_pydev_bundle/pydev_umd.py", line 198, in runfile
    pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
  File "pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "ConcreteNumpyAttempt1/test.py", line 19, in <module>
    multiplied = mul_circuit.run(added)
  File "ConcreteNumpyAttempt1/venv/lib/python3.10/site-packages/concrete/numpy/compilation/circuit.py", line 117, in run
    return self.server.run(args, self.client.evaluation_keys)
  File "ConcreteNumpyAttempt1/venv/lib/python3.10/site-packages/concrete/numpy/compilation/server.py", line 249, in run
    return self._support.server_call(self._server_lambda, args, evaluation_keys)
  File "ConcreteNumpyAttempt1/venv/lib/python3.10/site-packages/concrete/compiler/library_support.py", line 266, in server_call
    raise TypeError(
TypeError: public_arguments must be of type PublicArguments, not <class 'concrete.compiler.public_result.PublicResult'>

Answered on fhe.org discord

VReyes sorry for my mistake, we don’t yet have multiple output functions but you can make use of some other concrete-numpy features to achieve the same result :slight_smile: filling an array and reading it’s output at the right index

import concrete.numpy as cnp

def add(a, b):
    return a + b

def mul(a):
    return a * 2

@cnp.compiler({"a": "encrypted", "b": "encrypted"})
def add_then_mul_2(a, b):
    add_result = add(a, b)
    return cnp.array([add_result, mul(add_result)])

inputset = [(1,2), (3, 4)]
add_then_mul_2_circuit = add_then_mul_2.compile(inputset)

args = add_then_mul_2_circuit.encrypt(1, 2)
encrypted_res = add_then_mul_2_circuit.run(args)
res = add_then_mul_2_circuit.decrypt(encrypted_res)
print(res)

outputs

[3 6]