Predict

Predict test source.

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

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

enum { NINPUTS = 3, NOUTPUTS = 16 };


int main(void)
{
  int result = EXIT_SUCCESS;
  libxs_predict_t* model = libxs_predict_create(NINPUTS, NOUTPUTS);
  if (NULL == model) {
    result = EXIT_FAILURE;
  }
  else {
    const int nentries = 64;
    int i, j;
    for (i = 0; i < nentries && EXIT_SUCCESS == result; ++i) {
      double inputs[NINPUTS], outputs[NOUTPUTS];
      inputs[0] = 4.0 + (i % 8) * 4;
      inputs[1] = 4.0 + ((i / 8) % 8) * 4;
      inputs[2] = 4.0 + (i % 5) * 8;
      for (j = 0; j < NOUTPUTS; ++j) {
        outputs[j] = (double)((i + j * 3) % 7);
      }
      if (EXIT_SUCCESS != libxs_predict_push(NULL, model, inputs, outputs)) {
        result = EXIT_FAILURE;
      }
    }
    if (EXIT_SUCCESS == result) {
      result = libxs_predict_build(model, 0, 2, 0);
    }
    if (EXIT_SUCCESS == result) {
      libxs_predict_query_t qinfo;
      libxs_predict_query(model, &qinfo);
      FPRINTF(stderr, "Built: %d entries, %d clusters, order=%d\n",
        qinfo.nentries, qinfo.nclusters, qinfo.order);
      if (qinfo.nentries != nentries || qinfo.nclusters <= 0 || qinfo.order <= 0) {
        FPRINTF(stderr, "ERROR: unexpected query results\n");
        result = EXIT_FAILURE;
      }
    }
    if (EXIT_SUCCESS == result) {
      size_t size = 0;
      void* buffer = NULL;
      libxs_predict_t* loaded = NULL;
      if (EXIT_SUCCESS != libxs_predict_save(model, NULL, &size) || 0 == size) {
        FPRINTF(stderr, "ERROR: save size query failed\n");
        result = EXIT_FAILURE;
      }
      if (EXIT_SUCCESS == result) {
        buffer = malloc(size);
        if (NULL == buffer) {
          result = EXIT_FAILURE;
        }
      }
      if (EXIT_SUCCESS == result) {
        if (EXIT_SUCCESS != libxs_predict_save(model, buffer, &size)) {
          FPRINTF(stderr, "ERROR: save failed\n");
          result = EXIT_FAILURE;
        }
      }
      if (EXIT_SUCCESS == result) {
        loaded = libxs_predict_load(buffer, size);
        if (NULL == loaded) {
          FPRINTF(stderr, "ERROR: load failed\n");
          result = EXIT_FAILURE;
        }
      }
      if (EXIT_SUCCESS == result) {
        libxs_predict_query_t qi_orig, qi_load;
        libxs_predict_query(model, &qi_orig);
        libxs_predict_query(loaded, &qi_load);
        if (qi_orig.nentries != qi_load.nentries ||
            qi_orig.nclusters != qi_load.nclusters ||
            qi_orig.order != qi_load.order)
        {
          FPRINTF(stderr, "ERROR: query mismatch after load"
            " (entries %d/%d, clusters %d/%d, order %d/%d)\n",
            qi_orig.nentries, qi_load.nentries,
            qi_orig.nclusters, qi_load.nclusters,
            qi_orig.order, qi_load.order);
          result = EXIT_FAILURE;
        }
      }
      if (EXIT_SUCCESS == result) {
        size_t size2 = 0;
        void* buffer2 = NULL;
        libxs_predict_t* loaded2 = NULL;
        libxs_predict_save(loaded, NULL, &size2);
        buffer2 = malloc(size2);
        if (NULL != buffer2) {
          if (EXIT_SUCCESS == libxs_predict_save(loaded, buffer2, &size2)) {
            loaded2 = libxs_predict_load(buffer2, size2);
          }
        }
        if (NULL != loaded2) {
          for (i = 0; i < nentries && EXIT_SUCCESS == result; ++i) {
            double inputs[NINPUTS], out1[NOUTPUTS], out2[NOUTPUTS];
            inputs[0] = 4.0 + (i % 8) * 4;
            inputs[1] = 4.0 + ((i / 8) % 8) * 4;
            inputs[2] = 4.0 + (i % 5) * 8;
            libxs_predict_eval(NULL, loaded, inputs, out1, NULL, 1);
            libxs_predict_eval(NULL, loaded2, inputs, out2, NULL, 1);
            for (j = 0; j < NOUTPUTS; ++j) {
              const double delta = out1[j] - out2[j];
              if (delta > 1e-10 || delta < -1e-10) {
                FPRINTF(stderr, "ERROR: roundtrip mismatch at entry %d"
                  " output %d (%.6f vs %.6f)\n", i, j, out1[j], out2[j]);
                result = EXIT_FAILURE;
              }
            }
          }
          if (EXIT_SUCCESS == result) {
            double novel[NINPUTS], out1[NOUTPUTS], out2[NOUTPUTS];
            novel[0] = 14.0;
            novel[1] = 22.0;
            novel[2] = 18.0;
            libxs_predict_eval(NULL, loaded, novel, out1, NULL, 0);
            libxs_predict_eval(NULL, loaded2, novel, out2, NULL, 0);
            for (j = 0; j < NOUTPUTS; ++j) {
              const double delta = out1[j] - out2[j];
              if (delta > 1e-10 || delta < -1e-10) {
                FPRINTF(stderr, "ERROR: novel roundtrip mismatch at"
                  " output %d (%.6f vs %.6f)\n", j, out1[j], out2[j]);
                result = EXIT_FAILURE;
              }
            }
          }
          libxs_predict_destroy(loaded2);
        }
        else {
          FPRINTF(stderr, "ERROR: double roundtrip load failed\n");
          result = EXIT_FAILURE;
        }
        free(buffer2);
      }
      libxs_predict_destroy(loaded);
      free(buffer);
    }
    libxs_predict_destroy(model);
  }
  return result;
}