Fingerprint

Fingerprint test source.

/******************************************************************************
* Copyright (c) Intel Corporation - All rights reserved.                      *
* This file is part of the LIBXS library.                                     *
*                                                                             *
* For information on the license, see the LICENSE file.                       *
* Further information: https://github.com/hfp/libxs/                          *
* SPDX-License-Identifier: BSD-3-Clause                                       *
******************************************************************************/
#include <libxs_math.h>

#if defined(_DEBUG)
# define FPRINTF(STREAM, ...) do { fprintf(STREAM, __VA_ARGS__); } while(0)
#else
# define FPRINTF(STREAM, ...) do {} while(0)
#endif


int main(void)
{
  /* 1-D: constant array, all derivatives beyond order 0 should be zero */
  { double a[] = {5.0, 5.0, 5.0, 5.0, 5.0};
    const size_t shape[] = {5};
    libxs_fprint_t fa;
    if (EXIT_SUCCESS != libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 4, -1)) {
      FPRINTF(stderr, "ERROR line #%i: constant fprint failed\n", __LINE__);
      exit(EXIT_FAILURE);
    }
    if (4 != fa.order || 5 != fa.n) {
      FPRINTF(stderr, "ERROR line #%i: order=%d n=%d\n", __LINE__, fa.order, fa.n);
      exit(EXIT_FAILURE);
    }
    if (1E-12 > fa.l2[0]) {
      FPRINTF(stderr, "ERROR line #%i: constant norm[0]=%.17g\n", __LINE__, fa.l2[0]);
      exit(EXIT_FAILURE);
    }
    { int k;
      for (k = 1; k <= fa.order; ++k) {
        if (1E-10 < fa.l2[k]) {
          FPRINTF(stderr, "ERROR line #%i: constant norm[%d]=%.17g\n", __LINE__, k, fa.l2[k]);
          exit(EXIT_FAILURE);
        }
      }
    }
  }

  /* 1-D: linear ramp, order-1 norm nonzero, order>=2 should be zero */
  { double a[] = {0.0, 1.0, 2.0, 3.0, 4.0};
    const size_t shape[] = {5};
    libxs_fprint_t fa;
    if (EXIT_SUCCESS != libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 4, -1)) {
      FPRINTF(stderr, "ERROR line #%i: linear fprint failed\n", __LINE__);
      exit(EXIT_FAILURE);
    }
    if (1E-12 > fa.l2[0] || 1E-12 > fa.l2[1]) {
      FPRINTF(stderr, "ERROR line #%i: linear norm[0]=%.17g norm[1]=%.17g\n",
        __LINE__, fa.l2[0], fa.l2[1]);
      exit(EXIT_FAILURE);
    }
    { int k;
      for (k = 2; k <= fa.order; ++k) {
        if (1E-8 < fa.l2[k]) {
          FPRINTF(stderr, "ERROR line #%i: linear norm[%d]=%.17g\n", __LINE__, k, fa.l2[k]);
          exit(EXIT_FAILURE);
        }
      }
    }
  }

  /* 1-D: self-distance is zero */
  { double a[] = {1.0, 3.0, 2.0, 7.0, 5.0};
    const size_t shape[] = {5};
    libxs_fprint_t fa;
    double d;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 4, -1);
    d = libxs_fprint_diff(&fa, &fa, NULL);
    if (1E-15 < d) {
      FPRINTF(stderr, "ERROR line #%i: self-distance=%.17g\n", __LINE__, d);
      exit(EXIT_FAILURE);
    }
  }

  /* 1-D: identical data, different lengths */
  { double a5[] = {0.0, 1.0, 4.0, 9.0, 16.0};
    double a3[] = {0.0, 4.0, 16.0};
    const size_t s5[] = {5}, s3[] = {3};
    libxs_fprint_t f5, f3;
    libxs_fprint(&f5, LIBXS_DATATYPE_F64, a5, 1, s5, NULL, 2, -1);
    libxs_fprint(&f3, LIBXS_DATATYPE_F64, a3, 1, s3, NULL, 2, -1);
    FPRINTF(stderr, "INFO line #%i: quadratic 5vs3 dist=%.17g\n",
      __LINE__, libxs_fprint_diff(&f5, &f3, NULL));
  }

  /* 1-D: structurally different data yields nonzero distance */
  { double a[] = {1.0, 2.0, 3.0, 4.0};
    double b[] = {1.0, 4.0, 2.0, 8.0};
    const size_t shape[] = {4};
    libxs_fprint_t fa, fb;
    double d;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 3, -1);
    libxs_fprint(&fb, LIBXS_DATATYPE_F64, b, 1, shape, NULL, 3, -1);
    d = libxs_fprint_diff(&fa, &fb, NULL);
    if (1E-12 > d) {
      FPRINTF(stderr, "ERROR line #%i: different distance=%.17g\n", __LINE__, d);
      exit(EXIT_FAILURE);
    }
  }

  /* 1-D: symmetry d(a,b) == d(b,a) */
  { double a[] = {1.0, 4.0, 2.0, 8.0};
    double b[] = {2.0, 3.0, 5.0, 7.0};
    const size_t shape[] = {4};
    libxs_fprint_t fa, fb;
    double dab, dba;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 3, -1);
    libxs_fprint(&fb, LIBXS_DATATYPE_F64, b, 1, shape, NULL, 3, -1);
    dab = libxs_fprint_diff(&fa, &fb, NULL);
    dba = libxs_fprint_diff(&fb, &fa, NULL);
    if (1E-15 < LIBXS_DELTA(dab, dba)) {
      FPRINTF(stderr, "ERROR line #%i: symmetry dab=%.17g dba=%.17g\n", __LINE__, dab, dba);
      exit(EXIT_FAILURE);
    }
  }

  /* 1-D: custom weights */
  { double a[] = {1.0, 2.0, 3.0, 4.0};
    double b[] = {1.1, 2.1, 3.1, 4.1};
    double w[] = {1.0, 0.0, 0.0, 0.0};
    const size_t shape[] = {4};
    libxs_fprint_t fa, fb;
    double d_val, d_def;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 3, -1);
    libxs_fprint(&fb, LIBXS_DATATYPE_F64, b, 1, shape, NULL, 3, -1);
    d_val = libxs_fprint_diff(&fa, &fb, w);
    d_def = libxs_fprint_diff(&fa, &fb, NULL);
    if (1E-15 < LIBXS_DELTA(d_val, d_def) && d_val > d_def) {
      FPRINTF(stderr, "ERROR line #%i: value-only > default\n", __LINE__);
      exit(EXIT_FAILURE);
    }
  }

  /* 1-D: F32 type */
  { float a[] = {1.0f, 2.0f, 4.0f, 8.0f};
    const size_t shape[] = {4};
    libxs_fprint_t fa;
    if (EXIT_SUCCESS != libxs_fprint(&fa, LIBXS_DATATYPE_F32, a, 1, shape, NULL, 3, -1)) {
      FPRINTF(stderr, "ERROR line #%i: F32 fprint failed\n", __LINE__);
      exit(EXIT_FAILURE);
    }
    if (1E-12 > fa.l2[0]) {
      FPRINTF(stderr, "ERROR line #%i: F32 norm[0]=%.17g\n", __LINE__, fa.l2[0]);
      exit(EXIT_FAILURE);
    }
  }

  /* 1-D: I32 type */
  { int a[] = {10, 20, 30, 40};
    const size_t shape[] = {4};
    libxs_fprint_t fa;
    if (EXIT_SUCCESS != libxs_fprint(&fa, LIBXS_DATATYPE_I32, a, 1, shape, NULL, 2, -1)) {
      FPRINTF(stderr, "ERROR line #%i: I32 fprint failed\n", __LINE__);
      exit(EXIT_FAILURE);
    }
    if (1E-12 > fa.l2[0]) {
      FPRINTF(stderr, "ERROR line #%i: I32 norm[0]=%.17g\n", __LINE__, fa.l2[0]);
      exit(EXIT_FAILURE);
    }
  }

  /* 1-D: order clamped to n-1 */
  { double a[] = {1.0, 2.0};
    const size_t shape[] = {2};
    libxs_fprint_t fa;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 10, -1);
    if (1 != fa.order) {
      FPRINTF(stderr, "ERROR line #%i: clamp order=%d\n", __LINE__, fa.order);
      exit(EXIT_FAILURE);
    }
  }

  /* 1-D: single element */
  { double a[] = {42.0};
    const size_t shape[] = {1};
    libxs_fprint_t fa;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 5, -1);
    if (0 != fa.order || 1 != fa.n) {
      FPRINTF(stderr, "ERROR line #%i: single order=%d n=%d\n", __LINE__, fa.order, fa.n);
      exit(EXIT_FAILURE);
    }
    if (1E-12 > fa.l2[0]) {
      FPRINTF(stderr, "ERROR line #%i: single norm[0]=%.17g\n", __LINE__, fa.l2[0]);
      exit(EXIT_FAILURE);
    }
  }

  /* 2-D: identical matrices yield zero self-distance */
  { double m[] = {1.0, 2.0, 3.0,
                  4.0, 5.0, 6.0,
                  7.0, 8.0, 9.0,
                  10.0, 11.0, 12.0};
    const size_t shape[] = {3, 4};
    libxs_fprint_t fa, fb;
    double d;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, m, 2, shape, NULL, 2, -1);
    libxs_fprint(&fb, LIBXS_DATATYPE_F64, m, 2, shape, NULL, 2, -1);
    d = libxs_fprint_diff(&fa, &fb, NULL);
    if (1E-15 < d) {
      FPRINTF(stderr, "ERROR line #%i: 2D self-distance=%.17g\n", __LINE__, d);
      exit(EXIT_FAILURE);
    }
  }

  /* 2-D: different matrices yield nonzero distance */
  { double a[] = {1.0, 2.0, 3.0,
                  4.0, 5.0, 6.0};
    double b[] = {1.0, 9.0, 3.0,
                  4.0, 0.0, 6.0};
    const size_t shape[] = {3, 2};
    libxs_fprint_t fa, fb;
    double d;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 2, shape, NULL, 2, -1);
    libxs_fprint(&fb, LIBXS_DATATYPE_F64, b, 2, shape, NULL, 2, -1);
    d = libxs_fprint_diff(&fa, &fb, NULL);
    if (1E-12 > d) {
      FPRINTF(stderr, "ERROR line #%i: 2D different distance=%.17g\n", __LINE__, d);
      exit(EXIT_FAILURE);
    }
  }

  /* 2-D: symmetry */
  { double a[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    double b[] = {6.0, 5.0, 4.0, 3.0, 2.0, 1.0};
    const size_t shape[] = {3, 2};
    libxs_fprint_t fa, fb;
    double dab, dba;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 2, shape, NULL, 2, -1);
    libxs_fprint(&fb, LIBXS_DATATYPE_F64, b, 2, shape, NULL, 2, -1);
    dab = libxs_fprint_diff(&fa, &fb, NULL);
    dba = libxs_fprint_diff(&fb, &fa, NULL);
    if (1E-14 < LIBXS_DELTA(dab, dba)) {
      FPRINTF(stderr, "ERROR line #%i: 2D symmetry dab=%.17g dba=%.17g\n", __LINE__, dab, dba);
      exit(EXIT_FAILURE);
    }
  }

  /* 2-D with stride: column-major 3x2 with leading dimension 4 */
  { double m[] = {1.0, 2.0, 3.0, 99.0,
                  4.0, 5.0, 6.0, 99.0};
    const size_t shape[] = {3, 2};
    const size_t stride[] = {1, 4};
    double ref[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    const size_t rshape[] = {3, 2};
    libxs_fprint_t fm, fr;
    double d;
    libxs_fprint(&fm, LIBXS_DATATYPE_F64, m, 2, shape, stride, 2, -1);
    libxs_fprint(&fr, LIBXS_DATATYPE_F64, ref, 2, rshape, NULL, 2, -1);
    d = libxs_fprint_diff(&fm, &fr, NULL);
    if (1E-14 < d) {
      FPRINTF(stderr, "ERROR line #%i: 2D stride distance=%.17g\n", __LINE__, d);
      exit(EXIT_FAILURE);
    }
  }

  /* 2-D: different shapes are comparable */
  { double a[] = {1.0, 2.0, 3.0,
                  4.0, 5.0, 6.0};
    double b[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
                  7.0, 8.0, 9.0, 10.0, 11.0, 12.0};
    const size_t sa[] = {3, 2}, sb[] = {6, 2};
    libxs_fprint_t fa, fb;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 2, sa, NULL, 2, -1);
    libxs_fprint(&fb, LIBXS_DATATYPE_F64, b, 2, sb, NULL, 2, -1);
    FPRINTF(stderr, "INFO line #%i: 2D shape diff dist=%.17g\n",
      __LINE__, libxs_fprint_diff(&fa, &fb, NULL));
  }

  /* 3-D: smoke test */
  { double a[2*3*4];
    const size_t shape[] = {4, 3, 2};
    libxs_fprint_t fa;
    int i;
    for (i = 0; i < 24; ++i) a[i] = (double)(i * i);
    if (EXIT_SUCCESS != libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 3, shape, NULL, 2, -1)) {
      FPRINTF(stderr, "ERROR line #%i: 3D fprint failed\n", __LINE__);
      exit(EXIT_FAILURE);
    }
    if (1E-12 > fa.l2[0]) {
      FPRINTF(stderr, "ERROR line #%i: 3D norm[0]=%.17g\n", __LINE__, fa.l2[0]);
      exit(EXIT_FAILURE);
    }
  }

  /* N-D per-axis: 3D array, shape={3, 4, 2}, linear along axis 1 only.
   * m[i][j][k] = 1 + j  (j=0..3 is the only varying axis).
   * axis=0: constant along dim 0 -> all derivatives ~ 0
   * axis=1: linear along dim 1   -> d1 nonzero, d2+ ~ 0
   * axis=2: constant along dim 2 -> all derivatives ~ 0 */
  { double m[3 * 4 * 2];
    const size_t shape[] = {3, 4, 2};
    libxs_fprint_t fp;
    int i0, i1, i2, k, ax;
    for (i2 = 0; i2 < 2; ++i2)
      for (i1 = 0; i1 < 4; ++i1)
        for (i0 = 0; i0 < 3; ++i0)
          m[i2 * 12 + i1 * 3 + i0] = 1.0 + i1;
    for (ax = 0; ax < 3; ++ax) {
      if (EXIT_SUCCESS != libxs_fprint(&fp, LIBXS_DATATYPE_F64, m, 3, shape, NULL, 3, ax)) {
        FPRINTF(stderr, "ERROR line #%i: 3D axis=%d fprint failed\n", __LINE__, ax);
        exit(EXIT_FAILURE);
      }
      if (1 == ax) {
        if (1E-12 > fp.linf[1]) {
          FPRINTF(stderr, "ERROR line #%i: 3D axis=1 linf[1]=%.17g\n", __LINE__, fp.linf[1]);
          exit(EXIT_FAILURE);
        }
        for (k = 2; k <= fp.order; ++k) {
          if (1E-8 < fp.linf[k]) {
            FPRINTF(stderr, "ERROR line #%i: 3D axis=1 linf[%d]=%.17g\n", __LINE__, k, fp.linf[k]);
            exit(EXIT_FAILURE);
          }
        }
      }
      else {
        for (k = 1; k <= fp.order; ++k) {
          if (1E-10 < fp.linf[k]) {
            FPRINTF(stderr, "ERROR line #%i: 3D axis=%d linf[%d]=%.17g\n", __LINE__, ax, k, fp.linf[k]);
            exit(EXIT_FAILURE);
          }
        }
      }
    }
  }

  /* per-axis: libxs_fprint_raw recovers raw forward difference */
  { double a[] = {0.0, 10.0, 20.0, 30.0, 40.0};
    const size_t shape[] = {5};
    libxs_fprint_t fa;
    double raw_d1;
    libxs_fprint(&fa, LIBXS_DATATYPE_F64, a, 1, shape, NULL, 2, -1);
    raw_d1 = libxs_fprint_raw(&fa, 1, fa.linf[1]);
    if (1.0 < LIBXS_DELTA(raw_d1, 10.0)) {
      FPRINTF(stderr, "ERROR line #%i: raw d1=%.17g expected 10\n", __LINE__, raw_d1);
      exit(EXIT_FAILURE);
    }
  }

  return EXIT_SUCCESS;
}