Zigmoid

The zigmoid function is defined as follows:

\[\begin{split}zigmoid(x) = \left\{ \begin{array}\\ 0 & if\ x<-0.5 \\ x+0.5 & if\ -0.5\leq x \leq 0.5 \\ 1 & if x>0.5 \end{array} \right.\end{split}\]

It is an approximation to the sigmoid function, but easier to compute in the MPC context. It is further analagous to the “cut” function defined in the literature and similar to approximations used elsewhere such as in SecureML.

In this example, we secret share a vector of values selected to demonstrate the different piecewise separated areas of interest for the zigmoid function, and compute the zigmoid.

As always, Cicada’s zigmoid function operates element-wise on arrays of any shape.

[1]:
import logging

import numpy

from cicada.additive import AdditiveProtocolSuite
from cicada.communicator import SocketCommunicator
from cicada.logging import Logger

logging.basicConfig(level=logging.INFO)

def main(communicator):
    log = Logger(logging.getLogger(), communicator)
    protocol = AdditiveProtocolSuite(communicator)

    values = numpy.array([-5, -0.25, 0, 0.25, 5]) if communicator.rank == 0 else None
    log.info(f"Player {communicator.rank} values: {values}")

    values_share = protocol.share(secret=values, src=0, shape=(5,))
    zigmoid_share = protocol.zigmoid(values_share)
    zigmoid = protocol.reveal(zigmoid_share)

    log.info(f"Player {communicator.rank} zigmoid: {zigmoid}")

SocketCommunicator.run(world_size=2, fn=main);
INFO:root:Player 0 values: [-5.   -0.25  0.    0.25  5.  ]
INFO:root:Player 1 values: None
INFO:root:Player 0 zigmoid: [0.   0.25 0.5  0.75 1.  ]
INFO:root:Player 1 zigmoid: [0.   0.25 0.5  0.75 1.  ]