Skip to main content

Propagate Function

Name​

UxHwDoublePropagateFunction, UxHwFloatPropagateFunction — Propagate a distribution through a user-defined function.

Synopsis​

#include <stddef.h>
#include <uxhw.h>

void
UxHwDoublePropagateFunction(
void (*functionToPropagate)(void *, double *, size_t, double *, size_t),
void * functionArgs,
uncertain double * inputDistributionArray,
size_t numberOfInputDistributions,
uncertain double * outputDistributionArray,
size_t numberOfOutputDistributions);

void
UxHwFloatPropagateFunction(
void (*functionToPropagate)(void *, float *, size_t, float *, size_t),
void * functionArgs,
uncertain float * inputDistributionArray,
size_t numberOfInputDistributions,
uncertain float * outputDistributionArray,
size_t numberOfOutputDistributions);

Description​

UxHw-enabled hardware natively supports arithmetic and common unary and binary mathematical functions for distributional values. Users that require custom functionality that is not supported by the default operations can use UxHw<Double/Float>PropagateFunction to run them with distributional-valued variables. UxHw<Double/Float>PropagateFunction, on architectures that associate distributions with floating-point values, evaluates a user-defined functionToPropagate over a distribution array inputDistributionArray, with length numberOfInputDistributions, and writes the resulting distribution array into outputDistributionArray, with length numberOfOutputDistributions.

Computationally, this implies evaluating functionToPropagate over the inputDistributionArray joint distribution. In mathematical terms, this function evaluates the push-forward of the aforementioned joint distribution μ\mu:

X:=(X1,…,XN)∼μ⇒F(X;θ)=(F1(X;θ),…,FM(X;θ))∼F#μ\mathbf{X}:=(X_1,\ldots,X_N) \sim \mu \quad \Rightarrow \quad \mathbf{F}(\mathbf{X}; \boldsymbol{\theta})=(F_1(\mathbf{X};\boldsymbol{\theta}),\ldots,F_M(\mathbf{X};\boldsymbol{\theta})) \sim \mathbf{F}_{\#}\mu

where F\mathbf{F} is the functionToPropagate, θ\boldsymbol{\theta} is the functionArgs, X\mathbf{X} is the inputDistributionArray, N=N=numberOfInputDistributions, F(X)\mathbf{F}(\mathbf{X}) is the outputDistributionArray and M=M=numberOfOutputDistributions.

Notes​

  • Joint distribution creation, preceding function evaluation is core-dependent. Dependency-tracking cores (e.g., Jupiter) internally track the dependencies and their outputs do not lose dependency from the inputs.
  • PropagateFunction does not filter for NaN or Inf input values. Non-finite value behavior should be addressed in functionToPropagate.

Parameters​

  • (*functionToPropagate)(void *, <double/float> *, size_t, <double/float> *, size_t) — The user-defined function pointer for distribution propagation. If NULL, the function prints a warning and the function returns immediately.
  • functionArgs — Opaque pointer with user-defined function parameters. Non-distributional variables and constants should be added here.
  • inputDistributionArray — Array of distributions taken by functionToPropagate. If NULL, the function prints a warning and the function returns immediately.
  • numberOfInputDistributions — Number of elements in inputDistributionArray. If 0, the function prints a warning and the function returns immediately.
  • outputDistributionArray — Array of distributions returned by functionToPropagate. If NULL, the function prints a warning and the function returns immediately.
  • numberOfOutputDistributions — Number of elements in outputDistributionArray. If 0, the function prints a warning and the function returns immediately.

Return values​

UxHw<Double/Float>PropagateFunction returns void.

Suggested usage​

UxHw<Double/Float>PropagateFunction is especially useful when evaluating mathematical functions that contain control flow expressions, such as conditional and ternary operators. Likewise, mathematical functions defined in non-UxHw-compiled libraries must also be called through UxHw<Double/Float>PropagateFunction, as they do not natively support distributional values.

Examples​

Absolute value through PropagateFunction vs fabs native libm function​

#include <stdio.h>
#include <uxhw.h>
#include<math.h>

enum
{
kExampleInputCount = 1,
kExampleOutputCount = 1,
};

static void
absoluteValueKernel(void * arguments, double * inputs, size_t inputCount, double * outputs, size_t outputCount)
{
(void) arguments;
(void) inputCount;
(void) outputCount;

if (inputs[0] < 0.0)
{
outputs[0] = -inputs[0];
}
else
{
outputs[0] = inputs[0];
}

return;
}

int
main(void)
{
double x = UxHwDoubleGaussDist(0.0, 1.0);
double absoluteValue = 0.0;

UxHwDoublePropagateFunction(absoluteValueKernel, NULL, &x, kExampleInputCount, &absoluteValue, kExampleOutputCount);
printf(
"|x| (via PropagateFunction) = %lf\n"
"|x| (via native libm func.) = %lf\n",
absoluteValue,
fabs(x)
);

return 0;
}

Custom parametric function​

#include <stdio.h>
#include <uxhw.h>

/* Called once per joint input row: in[0..nIn), out[0..nOut) are plain doubles. */
static void
f(void *args, double *in, size_t nIn, double *out, size_t nOut)
{
double k = *(double *)args;

out[0] = k * in[0] + in[1]; /* linear */
out[1] = in[0] * in[1]; /* nonlinear */
}

int
main(void)
{
double k = 2.0;
double in[2] = {UxHwDoubleGaussDist(1.0, 0.1), UxHwDoubleUniformDist(0.0, 1.0)};
double out[2];

UxHwDoublePropagateFunction(f, &k, in, 2, out, 2);

printf("out[0] = %lf\n", out[0]);
printf("out[1] = %lf\n", out[1]);

return 0;
}