<commit_before>// -*- c++ -*-
// UjoImro, 2013
// Experimental code for the CARP Project
// Copyright (c) RealEyes, 2013
// This is a c-implementation of the PCA->MLP response map calculation

#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>

#include "mlp_impl.h"

static void copyMatFloatToArray(MatFloat In, int n, int m, float Out[][m]) {
  assert(In.rows == n);
  assert(In.cols == m);

  for (int i = 0; i < In.rows; i++)
    for (int j = 0; j < In.cols; j++)
      Out[i][j] = In.data[In.start + i * In.step + j];
}

static void copyMatCharToArray(MatChar In, int n, int m, uint8_t Out[][m]) {
  assert(In.rows == n);
  assert(In.cols == m);

  for (int i = 0; i < In.rows; i++)
    for (int j = 0; j < In.cols; j++)
      Out[i][j] = In.data[In.start + i * In.step + j];
}

static void copyArrayToMatFloat(int n, int m, float In[][m], MatFloat Out) {
  assert(Out.rows == n);
  assert(Out.cols == m);
  assert(Out.step == m);

  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      Out.data[Out.start + i * Out.step + j] = In[i][j];
}

static void copyArrayToMatChar(int n, int m, uint8_t In[][m], MatChar Out) {
  assert(Out.rows == n);
  assert(Out.cols == m);
  assert(Out.step == m);

  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      Out.data[Out.start + i * Out.step + j] = In[i][j];
}

void printArray(int n, int m, float Array[n][m]) {
  printf("%s = [\n", "NAME");

  int q, w;

  for (q = 0; q < n; q++) {
    printf("[ ");
    for (w = 0; w < m; w++) {
      printf("%f, ", Array[n][m]);
    }
    printf(" ]\n");
  }

  printf("]\n");

  return;
}

float GetValueFloat(MatFloat self, int row, int col);

void printMatFloat(MatFloat mat, char *name) {
  printf("%s = [\n", name);

  int q, w;

  for (q = 0; q < mat.rows; q++) {
    printf("[ ");
    for (w = 0; w < mat.cols; w++) {
      printf("%f, ", GetValueFloat(mat, q, w));
    }
    printf(" ]\n");
  }

  printf("]\n");

  return;
}

void freeMLP(mlp *classifier) {
  freeMatFloat(&classifier->m_wIn);
  freeMatFloat(&classifier->m_wOut);
  freeMatFloat(&classifier->m_U);
}

MatFloat CreateMatFloat(int rows, int cols) {
  MatFloat result;
  assert(rows > 0);
  assert(cols > 0);

  result.data = NULL;
  result.data = (float *)malloc(sizeof(float) * rows * cols);
  assert(result.data);
  result.rows = rows;
  result.cols = cols;
  result.step = cols;
  result.start = 0;

  return result;
}

MatChar CreateMatChar(int rows, int cols) {
  MatChar result;
  assert(rows > 0);
  assert(cols > 0);

  result.data = NULL;
  result.data = (uint8_t *)malloc(sizeof(uint8_t) * rows * cols);
  assert(result.data);
  result.rows = rows;
  result.cols = cols;
  result.step = cols;
  result.start = 0;

  return result;
}

static void transposeFloat(MatFloat input, MatFloat *output) {
  int q, w;
  assert(output->rows == input.cols);
  assert(output->cols == input.rows);
  for (q = 0; q < input.rows; q++)
    for (w = 0; w < input.cols; w++)
      output->data[w * output->step + q + output->start] =
          input.data[q * input.step + w + input.start];
}

static void transposeFloatArray(int InRows, int InCols,
                                float In[InRows][InCols], int OutRows,
                                int OutCols, float Out[OutRows][OutCols]) {
  assert(InRows == OutCols);
  assert(OutCols == InRows);

  for (int i = 0; i < InRows; i++)
    for (int j = 0; j < InCols; j++)
	Out[j][i] = In[i][j];

  return;
}

static float meanChar(int Rows, int Cols, uint8_t M[Rows][Cols]) {
  float sum = 0;

  for (int i = 0; i < Rows; i++)
    for (int j = 0; j < Cols; j++) {
      sum += M[i][j];
    }

  return sum / (Rows * Cols);
}

static uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; }

static uint8_t minChar(int Rows, int Cols, uint8_t M[Rows][Cols]) {
  uint8_t minvalue = 255;

  for (int i = 0; i < Rows; i++)
    for (int j = 0; j < Cols; j++)
      minvalue = min(minvalue, M[i][j]);

  return minvalue;
}

static uint8_t max(uint8_t a, uint8_t b) { return a > b ? a : b; }

static uint8_t maxChar(int Rows, int Cols, uint8_t M[Rows][Cols]) {
  uint8_t maxvalue = 0;

  for (int i = 0; i < Rows; i++)
    for (int j = 0; j < Cols; j++)
      maxvalue = max(maxvalue, M[i][j]);

  return maxvalue;
}

static MatChar GetBlockChar(MatChar self, int row_from, int row_to,
                            int col_from, int col_to) {
  assert(row_from >= 0);
  assert(col_from >= 0);
  assert(row_from < row_to);
  assert(col_from < col_to);
  assert(row_to <= self.rows);
  assert(col_to <= self.cols);
  assert(self.data);

  MatChar result;
  result.rows = row_to - row_from;
  result.cols = col_to - col_from;
  result.step = self.step;
  result.start = self.start + row_from * self.step + col_from;
  result.data = self.data;

  return result;
}

static MatFloat GetBlockFloat(MatFloat self, int row_from, int row_to,
                              int col_from, int col_to) {
  assert(row_from >= 0);
  assert(col_from >= 0);
  assert(row_from < row_to);
  assert(col_from < col_to);
  assert(row_to <= self.rows);
  assert(col_to <= self.cols);
  assert(self.data);

  MatFloat result;
  result.rows = row_to - row_from;
  result.cols = col_to - col_from;
  result.step = self.step;
  result.start = self.start + row_from * self.step + col_from;
  result.data = self.data;

  return result;
}

static void convertFromCharToFloatArray(int InRows, int InCols,
                                        uint8_t In[InRows][InCols],
                                        float quotient, float shift,
                                        int OutRows, int OutCols,
                                        float Out[OutRows][OutCols]) {
  assert(InRows == OutRows);
  assert(InCols == OutCols);

  for (int i = 0; i < InRows; i++)
    for (int j = 0; j < InCols; j++)
      Out[i][j] = quotient * (float)In[i][j] + shift;
  return;
}

void freeMatFloat(MatFloat *mat) {
  assert(mat->data);
  assert(mat->start == 0);
  free(mat->data);
  mat->data = NULL;
  mat->rows = 0;
  mat->cols = 0;
  mat->step = 0;
  mat->start = 0;
  return;
}

void freeMatChar(MatChar *mat) {
  assert(mat->data);
  assert(mat->start == 0);
  free(mat->data);
  mat->data = NULL;
  mat->rows = 0;
  mat->cols = 0;
  mat->step = 0;
  mat->start = 0;
  return;
}

// returns alpha*A*B + beta * C
static void gemmFloat(MatFloat A, MatFloat B, float alpha, MatFloat C,
                      float beta, MatFloat *result) {
  assert(A.rows == C.rows);
  assert(A.cols == B.rows);
  assert(B.cols == C.cols);
  assert(C.rows == result->rows);
  assert(C.cols == result->cols);

  float sum = 0;

  for (int q = 0; q < C.rows; q++)
    for (int w = 0; w < C.cols; w++) {
      sum = 0;
      for (int e = 0; e < A.cols; e++) {
        sum += A.data[q * A.step + e + A.start] *
                      B.data[e * B.step + w + B.start];
      }

      result->data[q * result->step + w + result->start] =
          alpha * sum + beta * C.data[q * C.step + w + C.start];
    }

  return;
}

// returns alpha*A*B + beta * C
static void gemmFloatArray(int ARows, int ACols, float A[ARows][ACols],
                           int BRows, int BCols, float B[ARows][BCols],
                           float alpha, int CRows, int CCols,
                           float C[CRows][CCols], float beta, int ResRows,
                           int ResCols, float Res[ResRows][ResCols]) {
  assert(ARows == CRows);
  assert(ACols == BRows);
  assert(BCols == CCols);
  assert(CRows == ResRows);
  assert(CCols == ResCols);

  for (int i = 0; i < CRows; i++)
    for (int j = 0; j < CCols; j++) {
      Res[i][j] = beta * C[i][j];
      for (int k = 0; k < ACols; k++) {
        Res[i][j] += alpha * A[i][k] * B[k][j];
      }
    }

  return;
}

static void expFloat(int rows, int cols, float Mat[rows][cols]) {

  for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
      Mat[i][j] = expf(Mat[i][j]);

  return;
}

static void addFloat(int rows, int cols, float Mat[rows][cols], float Val) {

  for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
      Mat[i][j] = Val + Mat[i][j];

  return;
}

static void divideFloat(float Val, int rows, int cols, float Mat[rows][cols]) {

  for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
      Mat[i][j] = Val / Mat[i][j];

  return;
}

float GetValueFloat(MatFloat self, int row, int col) {
  return self.data[row * self.step + col + self.start];
}

static void SetValueFloat(MatFloat *self, int row, int col, float value) {
  self->data[row * self->step + col + self->start] = value;
  return;
}

static float dotProduct(int LeftRows, int LeftCols, int RightRows,
                        int RightCols, float Left[][LeftCols],
                        float Right[][RightCols]) {
  assert(LeftCols == 1);
  assert(RightCols == 1);
  assert(LeftRows == RightRows);

  float Result = 0.;

  for (int i = 0; i < LeftRows; i++) {
    Result += Left[i][0] * Right[i][0];
  }

  return Result;
}

static void normalizeSample(int imageRows, int imageCols,
                            uint8_t imageArray[imageRows][imageCols],
                            int resultRows, int resultCols,
                            float resultArray[resultRows][resultCols]) {

  float sampleMean = meanChar(imageRows, imageCols, imageArray);
  float sampleMin = minChar(imageRows, imageCols, imageArray);
  float sampleMax = maxChar(imageRows, imageCols, imageArray);

  sampleMax -= sampleMean;
  sampleMin -= sampleMean;

  sampleMax = fmaxf(fabsf(sampleMin), fabsf(sampleMax));

  if (sampleMax == 0.0)
    sampleMax = 1.0;

  convertFromCharToFloatArray(imageRows, imageCols, imageArray, 1.0 / sampleMax,
                              -(1.0 / sampleMax) * sampleMean, resultRows,
                              resultCols, resultArray);
  return;
}

static void copySubArrayChar(int arrayRows, int arrayCols,
                             uint8_t Array[arrayRows][arrayCols],
                             int subArrayRows, int subArrayCols,
                             uint8_t subArray[subArrayRows][subArrayCols],
                             int offsetRow, int offsetCol) {
  for (int i = 0; i < subArrayRows; i++)
    for (int j = 0; j < subArrayCols; j++)
      subArray[i][j] = Array[i + offsetRow][j + offsetCol];
}

static void copySubArrayFloat(int arrayRows, int arrayCols,
                              float Array[arrayRows][arrayCols],
                              int subArrayRows, int subArrayCols,
                              float subArray[subArrayRows][subArrayCols],
                              int offsetRow, int offsetCol) {
  for (int i = 0; i < subArrayRows; i++)
    for (int j = 0; j < subArrayCols; j++)
      subArray[i][j] = Array[i + offsetRow][j + offsetCol];
}

/// @brief Calculate a single response map for an image.
///
/// @param Image The image to process.
static void generateResponseMap(
    int ImageRows, int ImageCols, uint8_t Image[ImageRows][ImageCols],
    const Point2i center, int mapSize, mlp classifier,
    float ResponseMap[mapSize + mapSize + 1][mapSize + mapSize + 1]) {

  MatFloat m_U_transpose =
      CreateMatFloat(classifier.m_U.cols, classifier.m_U.rows);
  transposeFloat(classifier.m_U, &m_U_transpose);

  // Subarray
  //
  // This function defines a sub array of a given 2D array. We need to
  // represent this in some way.
  MatFloat wIn_A = GetBlockFloat(classifier.m_wIn, 0, classifier.m_wIn.rows, 0,
                                 classifier.m_wIn.cols - 1);
  MatFloat wIn = CreateMatFloat(wIn_A.rows, m_U_transpose.cols);
  gemmFloat(wIn_A, m_U_transpose, 1.0, wIn, 0.0, &wIn);

  int wInRows = wIn.rows;
  int wInCols = wIn.cols;
  float (*wInArray)[wInCols] = malloc(sizeof(float) * wInRows * wInCols);
  copyMatFloatToArray(wIn, wInRows, wInCols, wInArray);

  // Subarray
  MatFloat bIn =
      GetBlockFloat(classifier.m_wIn, 0, classifier.m_wIn.rows,
                    classifier.m_wIn.cols - 1, classifier.m_wIn.cols);

  int m_wOutRows = classifier.m_wOut.rows;
  int m_wOutCols = classifier.m_wOut.cols;
  float (*m_wOutArray)[m_wOutCols] =
      malloc(sizeof(float) * m_wOutRows * m_wOutCols);
  copyMatFloatToArray(classifier.m_wOut, m_wOutRows, m_wOutCols, m_wOutArray);

  int wOut_tmpRows = m_wOutRows;
  int wOut_tmpCols = m_wOutCols - 1;
  float (*wOut_tmpArray)[wOut_tmpCols] = malloc(sizeof(float) * wOut_tmpRows * wOut_tmpCols);

  copySubArrayFloat(m_wOutRows, m_wOutCols, m_wOutArray, wOut_tmpRows,
                    wOut_tmpCols, wOut_tmpArray, 0, 0);

  int wOutRows = wOut_tmpCols;
  int wOutCols = wOut_tmpRows;
  float (*wOutArray)[wOutCols] = malloc(sizeof(float) * wOutRows * wOutCols);
  transposeFloatArray(wOut_tmpRows, wOut_tmpCols, wOut_tmpArray, wOutRows,
                      wOutCols, wOutArray);

  int bInRows = bIn.rows;
  int bInCols = bIn.cols;
  float (*bInArray)[bInCols] = malloc(sizeof(float) * bInRows * bInCols);
  copyMatFloatToArray(bIn, bInRows, bInCols, bInArray);

  float bOut = GetValueFloat(classifier.m_wOut, 0, classifier.m_wOut.cols - 1);

  for (int ncy = 0; ncy <= 2 * mapSize; ++ncy) {
    int cy = ncy + center.y - mapSize;
    for (int ncx = 0; ncx <= 2 * mapSize; ++ncx) {
      int cx = ncx + center.x - mapSize;<commit_msg>Switch another element to C99 arrays<commit_after>// -*- c++ -*-
// UjoImro, 2013
// Experimental code for the CARP Project
// Copyright (c) RealEyes, 2013
// This is a c-implementation of the PCA->MLP response map calculation

#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>

#include "mlp_impl.h"

static void copyMatFloatToArray(MatFloat In, int n, int m, float Out[][m]) {
  assert(In.rows == n);
  assert(In.cols == m);

  for (int i = 0; i < In.rows; i++)
    for (int j = 0; j < In.cols; j++)
      Out[i][j] = In.data[In.start + i * In.step + j];
}

static void copyMatCharToArray(MatChar In, int n, int m, uint8_t Out[][m]) {
  assert(In.rows == n);
  assert(In.cols == m);

  for (int i = 0; i < In.rows; i++)
    for (int j = 0; j < In.cols; j++)
      Out[i][j] = In.data[In.start + i * In.step + j];
}

static void copyArrayToMatFloat(int n, int m, float In[][m], MatFloat Out) {
  assert(Out.rows == n);
  assert(Out.cols == m);
  assert(Out.step == m);

  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      Out.data[Out.start + i * Out.step + j] = In[i][j];
}

static void copyArrayToMatChar(int n, int m, uint8_t In[][m], MatChar Out) {
  assert(Out.rows == n);
  assert(Out.cols == m);
  assert(Out.step == m);

  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      Out.data[Out.start + i * Out.step + j] = In[i][j];
}

void printArray(int n, int m, float Array[n][m]) {
  printf("%s = [\n", "NAME");

  int q, w;

  for (q = 0; q < n; q++) {
    printf("[ ");
    for (w = 0; w < m; w++) {
      printf("%f, ", Array[n][m]);
    }
    printf(" ]\n");
  }

  printf("]\n");

  return;
}

float GetValueFloat(MatFloat self, int row, int col);

void printMatFloat(MatFloat mat, char *name) {
  printf("%s = [\n", name);

  int q, w;

  for (q = 0; q < mat.rows; q++) {
    printf("[ ");
    for (w = 0; w < mat.cols; w++) {
      printf("%f, ", GetValueFloat(mat, q, w));
    }
    printf(" ]\n");
  }

  printf("]\n");

  return;
}

void freeMLP(mlp *classifier) {
  freeMatFloat(&classifier->m_wIn);
  freeMatFloat(&classifier->m_wOut);
  freeMatFloat(&classifier->m_U);
}

MatFloat CreateMatFloat(int rows, int cols) {
  MatFloat result;
  assert(rows > 0);
  assert(cols > 0);

  result.data = NULL;
  result.data = (float *)malloc(sizeof(float) * rows * cols);
  assert(result.data);
  result.rows = rows;
  result.cols = cols;
  result.step = cols;
  result.start = 0;

  return result;
}

MatChar CreateMatChar(int rows, int cols) {
  MatChar result;
  assert(rows > 0);
  assert(cols > 0);

  result.data = NULL;
  result.data = (uint8_t *)malloc(sizeof(uint8_t) * rows * cols);
  assert(result.data);
  result.rows = rows;
  result.cols = cols;
  result.step = cols;
  result.start = 0;

  return result;
}

static void transposeFloat(MatFloat input, MatFloat *output) {
  int q, w;
  assert(output->rows == input.cols);
  assert(output->cols == input.rows);
  for (q = 0; q < input.rows; q++)
    for (w = 0; w < input.cols; w++)
      output->data[w * output->step + q + output->start] =
          input.data[q * input.step + w + input.start];
}

static void transposeFloatArray(int InRows, int InCols,
                                float In[InRows][InCols], int OutRows,
                                int OutCols, float Out[OutRows][OutCols]) {
  assert(InRows == OutCols);
  assert(OutCols == InRows);

  for (int i = 0; i < InRows; i++)
    for (int j = 0; j < InCols; j++)
	Out[j][i] = In[i][j];

  return;
}

static float meanChar(int Rows, int Cols, uint8_t M[Rows][Cols]) {
  float sum = 0;

  for (int i = 0; i < Rows; i++)
    for (int j = 0; j < Cols; j++) {
      sum += M[i][j];
    }

  return sum / (Rows * Cols);
}

static uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; }

static uint8_t minChar(int Rows, int Cols, uint8_t M[Rows][Cols]) {
  uint8_t minvalue = 255;

  for (int i = 0; i < Rows; i++)
    for (int j = 0; j < Cols; j++)
      minvalue = min(minvalue, M[i][j]);

  return minvalue;
}

static uint8_t max(uint8_t a, uint8_t b) { return a > b ? a : b; }

static uint8_t maxChar(int Rows, int Cols, uint8_t M[Rows][Cols]) {
  uint8_t maxvalue = 0;

  for (int i = 0; i < Rows; i++)
    for (int j = 0; j < Cols; j++)
      maxvalue = max(maxvalue, M[i][j]);

  return maxvalue;
}

static MatChar GetBlockChar(MatChar self, int row_from, int row_to,
                            int col_from, int col_to) {
  assert(row_from >= 0);
  assert(col_from >= 0);
  assert(row_from < row_to);
  assert(col_from < col_to);
  assert(row_to <= self.rows);
  assert(col_to <= self.cols);
  assert(self.data);

  MatChar result;
  result.rows = row_to - row_from;
  result.cols = col_to - col_from;
  result.step = self.step;
  result.start = self.start + row_from * self.step + col_from;
  result.data = self.data;

  return result;
}

static MatFloat GetBlockFloat(MatFloat self, int row_from, int row_to,
                              int col_from, int col_to) {
  assert(row_from >= 0);
  assert(col_from >= 0);
  assert(row_from < row_to);
  assert(col_from < col_to);
  assert(row_to <= self.rows);
  assert(col_to <= self.cols);
  assert(self.data);

  MatFloat result;
  result.rows = row_to - row_from;
  result.cols = col_to - col_from;
  result.step = self.step;
  result.start = self.start + row_from * self.step + col_from;
  result.data = self.data;

  return result;
}

static void convertFromCharToFloatArray(int InRows, int InCols,
                                        uint8_t In[InRows][InCols],
                                        float quotient, float shift,
                                        int OutRows, int OutCols,
                                        float Out[OutRows][OutCols]) {
  assert(InRows == OutRows);
  assert(InCols == OutCols);

  for (int i = 0; i < InRows; i++)
    for (int j = 0; j < InCols; j++)
      Out[i][j] = quotient * (float)In[i][j] + shift;
  return;
}

void freeMatFloat(MatFloat *mat) {
  assert(mat->data);
  assert(mat->start == 0);
  free(mat->data);
  mat->data = NULL;
  mat->rows = 0;
  mat->cols = 0;
  mat->step = 0;
  mat->start = 0;
  return;
}

void freeMatChar(MatChar *mat) {
  assert(mat->data);
  assert(mat->start == 0);
  free(mat->data);
  mat->data = NULL;
  mat->rows = 0;
  mat->cols = 0;
  mat->step = 0;
  mat->start = 0;
  return;
}

// returns alpha*A*B + beta * C
static void gemmFloat(MatFloat A, MatFloat B, float alpha, MatFloat C,
                      float beta, MatFloat *result) {
  assert(A.rows == C.rows);
  assert(A.cols == B.rows);
  assert(B.cols == C.cols);
  assert(C.rows == result->rows);
  assert(C.cols == result->cols);

  float sum = 0;

  for (int q = 0; q < C.rows; q++)
    for (int w = 0; w < C.cols; w++) {
      sum = 0;
      for (int e = 0; e < A.cols; e++) {
        sum += A.data[q * A.step + e + A.start] *
                      B.data[e * B.step + w + B.start];
      }

      result->data[q * result->step + w + result->start] =
          alpha * sum + beta * C.data[q * C.step + w + C.start];
    }

  return;
}

// returns alpha*A*B + beta * C
static void gemmFloatArray(int ARows, int ACols, float A[ARows][ACols],
                           int BRows, int BCols, float B[ARows][BCols],
                           float alpha, int CRows, int CCols,
                           float C[CRows][CCols], float beta, int ResRows,
                           int ResCols, float Res[ResRows][ResCols]) {
  assert(ARows == CRows);
  assert(ACols == BRows);
  assert(BCols == CCols);
  assert(CRows == ResRows);
  assert(CCols == ResCols);

  for (int i = 0; i < CRows; i++)
    for (int j = 0; j < CCols; j++) {
      Res[i][j] = beta * C[i][j];
      for (int k = 0; k < ACols; k++) {
        Res[i][j] += alpha * A[i][k] * B[k][j];
      }
    }

  return;
}

static void expFloat(int rows, int cols, float Mat[rows][cols]) {

  for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
      Mat[i][j] = expf(Mat[i][j]);

  return;
}

static void addFloat(int rows, int cols, float Mat[rows][cols], float Val) {

  for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
      Mat[i][j] = Val + Mat[i][j];

  return;
}

static void divideFloat(float Val, int rows, int cols, float Mat[rows][cols]) {

  for (int i = 0; i < rows; i++)
    for (int j = 0; j < cols; j++)
      Mat[i][j] = Val / Mat[i][j];

  return;
}

float GetValueFloat(MatFloat self, int row, int col) {
  return self.data[row * self.step + col + self.start];
}

static void SetValueFloat(MatFloat *self, int row, int col, float value) {
  self->data[row * self->step + col + self->start] = value;
  return;
}

static float dotProduct(int LeftRows, int LeftCols, int RightRows,
                        int RightCols, float Left[][LeftCols],
                        float Right[][RightCols]) {
  assert(LeftCols == 1);
  assert(RightCols == 1);
  assert(LeftRows == RightRows);

  float Result = 0.;

  for (int i = 0; i < LeftRows; i++) {
    Result += Left[i][0] * Right[i][0];
  }

  return Result;
}

static void normalizeSample(int imageRows, int imageCols,
                            uint8_t imageArray[imageRows][imageCols],
                            int resultRows, int resultCols,
                            float resultArray[resultRows][resultCols]) {

  float sampleMean = meanChar(imageRows, imageCols, imageArray);
  float sampleMin = minChar(imageRows, imageCols, imageArray);
  float sampleMax = maxChar(imageRows, imageCols, imageArray);

  sampleMax -= sampleMean;
  sampleMin -= sampleMean;

  sampleMax = fmaxf(fabsf(sampleMin), fabsf(sampleMax));

  if (sampleMax == 0.0)
    sampleMax = 1.0;

  convertFromCharToFloatArray(imageRows, imageCols, imageArray, 1.0 / sampleMax,
                              -(1.0 / sampleMax) * sampleMean, resultRows,
                              resultCols, resultArray);
  return;
}

static void copySubArrayChar(int arrayRows, int arrayCols,
                             uint8_t Array[arrayRows][arrayCols],
                             int subArrayRows, int subArrayCols,
                             uint8_t subArray[subArrayRows][subArrayCols],
                             int offsetRow, int offsetCol) {
  for (int i = 0; i < subArrayRows; i++)
    for (int j = 0; j < subArrayCols; j++)
      subArray[i][j] = Array[i + offsetRow][j + offsetCol];
}

static void copySubArrayFloat(int arrayRows, int arrayCols,
                              float Array[arrayRows][arrayCols],
                              int subArrayRows, int subArrayCols,
                              float subArray[subArrayRows][subArrayCols],
                              int offsetRow, int offsetCol) {
  for (int i = 0; i < subArrayRows; i++)
    for (int j = 0; j < subArrayCols; j++)
      subArray[i][j] = Array[i + offsetRow][j + offsetCol];
}

/// @brief Calculate a single response map for an image.
///
/// @param Image The image to process.
static void generateResponseMap(
    int ImageRows, int ImageCols, uint8_t Image[ImageRows][ImageCols],
    const Point2i center, int mapSize, mlp classifier,
    float ResponseMap[mapSize + mapSize + 1][mapSize + mapSize + 1]) {

  MatFloat m_U_transpose =
      CreateMatFloat(classifier.m_U.cols, classifier.m_U.rows);
  transposeFloat(classifier.m_U, &m_U_transpose);

  // Subarray
  //
  // This function defines a sub array of a given 2D array. We need to
  // represent this in some way.
  MatFloat wIn_A = GetBlockFloat(classifier.m_wIn, 0, classifier.m_wIn.rows, 0,
                                 classifier.m_wIn.cols - 1);
  MatFloat wIn = CreateMatFloat(wIn_A.rows, m_U_transpose.cols);
  gemmFloat(wIn_A, m_U_transpose, 1.0, wIn, 0.0, &wIn);

  int wInRows = wIn.rows;
  int wInCols = wIn.cols;
  float (*wInArray)[wInCols] = malloc(sizeof(float) * wInRows * wInCols);
  copyMatFloatToArray(wIn, wInRows, wInCols, wInArray);

  // Subarray
  MatFloat bIn =
      GetBlockFloat(classifier.m_wIn, 0, classifier.m_wIn.rows,
                    classifier.m_wIn.cols - 1, classifier.m_wIn.cols);

  int m_wOutRows = classifier.m_wOut.rows;
  int m_wOutCols = classifier.m_wOut.cols;
  float (*m_wOutArray)[m_wOutCols] =
      malloc(sizeof(float) * m_wOutRows * m_wOutCols);
  copyMatFloatToArray(classifier.m_wOut, m_wOutRows, m_wOutCols, m_wOutArray);

  int wOut_tmpRows = m_wOutRows;
  int wOut_tmpCols = m_wOutCols - 1;
  float (*wOut_tmpArray)[wOut_tmpCols] = malloc(sizeof(float) * wOut_tmpRows * wOut_tmpCols);

  copySubArrayFloat(m_wOutRows, m_wOutCols, m_wOutArray, wOut_tmpRows,
                    wOut_tmpCols, wOut_tmpArray, 0, 0);

  int wOutRows = wOut_tmpCols;
  int wOutCols = wOut_tmpRows;
  float (*wOutArray)[wOutCols] = malloc(sizeof(float) * wOutRows * wOutCols);
  transposeFloatArray(wOut_tmpRows, wOut_tmpCols, wOut_tmpArray, wOutRows,
                      wOutCols, wOutArray);

  int bInRows = bIn.rows;
  int bInCols = bIn.cols;
  float (*bInArray)[bInCols] = malloc(sizeof(float) * bInRows * bInCols);
  copyMatFloatToArray(bIn, bInRows, bInCols, bInArray);

  float bOut = m_wOutArray[0][m_wOutCols - 1];

  for (int ncy = 0; ncy <= 2 * mapSize; ++ncy) {
    int cy = ncy + center.y - mapSize;
    for (int ncx = 0; ncx <= 2 * mapSize; ++ncx) {
      int cx = ncx + center.x - mapSize;
{'fraction_non_alphanumeric': 0.15091566809857562, 'fraction_numerical': 0.01009872635466124, 'mean_word_length': 2.5598926894701544, 'pattern_counts': {'":': 0, '<': 117, '<?xml version=': 0, '>': 97, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2918152', 'n_tokens_mistral': 10132, 'n_tokens_neox': 9731, 'n_words': 2550}