Correlation

The correlation metric is useful to judge the prediction accuracy when responses are non-binary, e.g. when studying Integrated Optical PUFs.

>>> import pypuf.simulation, pypuf.io, pypuf.attack, pypuf.metrics
>>> puf = pypuf.simulation.IntegratedOpticalPUF(n=64, m=25, seed=1)
>>> crps = pypuf.io.ChallengeResponseSet.from_simulation(puf, N=1000, seed=2)
>>> crps_test = pypuf.io.ChallengeResponseSet.from_simulation(puf, N=1000, seed=3)
>>> feature_map = pypuf.attack.LeastSquaresRegression.feature_map_optical_pufs_reloaded_improved
>>> model = pypuf.attack.LeastSquaresRegression(crps, feature_map=feature_map).fit()
>>> pypuf.metrics.correlation(model, crps_test).mean()
0.69...

Note that the correlation can differ when additionally, post-processing of the responses is performed, e.g. by thresholding the values such that half the values give -1 and the other half 1:

>>> import numpy as np
>>> threshold = lambda r: np.sign(r - np.quantile(r.flatten(), .5))
>>> pypuf.metrics.correlation(model, crps_test, postprocessing=threshold).mean()
0.41...
pypuf.metrics.correlation(simulation: ~pypuf.simulation.base.Simulation, test_set: ~pypuf.io.ChallengeResponseSet, postprocessing: ~typing.Callable[[~numpy.ndarray], ~numpy.ndarray] | None = <function postprocessing_noop>) ndarray

Evaluates the given simulation on the challenges defined in the test_set and computes the correlations of the response pixels.

pypuf.metrics.correlation_data(responses1: ~numpy.ndarray, responses2: ~numpy.ndarray, postprocessing: ~typing.Callable[[~numpy.ndarray], ~numpy.ndarray] | None = <function postprocessing_noop>) ndarray

Given two versions responses1 and responses2 of \(N\) responses of \(m\) pixels each, the \(m\) Pearson corrleations of the response pixels are returned. If any postprocessing function is given, it is applied to both responses1 and responses2 before the correlations are computed.

>>> import numpy as np
>>> import pypuf.metrics
>>> responses1 = np.array([[-1, -1, -1, 1], [1, 1, 1, -1]])
>>> responses2 = np.array([[-1, -1, -1, 1], [1, 1, 1, -1]])
>>> pypuf.metrics.correlation_data(responses1, responses2)
array([1., 1., 1., 1.], dtype=float32)
>>> responses1 = np.array([[-1], [-1], [1], [1]])
>>> responses2 = np.array([[1], [1], [-1], [-1]])
>>> pypuf.metrics.correlation_data(responses1, responses2)
array([-1.], dtype=float32)