// A rectangular block of data of type float.  A transparent block
// cache is used for each instance of this class if necessary, so the
// image can be much bigger than will fit in memory, and pixels can
// still be accessed and written efficiently, provided subsequent
// accesses are spatially correlated.  A variety of useful methods are
// implemented (filtering, subsetting, interpolating, etc.)
//
// Don't try to access the same instance concurrently.  Split your
// images up into separate instances if you must parallelize things.
//
// For many methods, arguments of type ssize_t are used, but are not
// allowed to be negative.  This is to help prevent people from
// shooting themselves in the foor by accidently passing negative
// values which don't yield warnings and can't be caught with
// assertions.

#ifndef FLOAT_IMAGE_H
#define FLOAT_IMAGE_H

#ifndef solaris
#  include <stdint.h>
#endif
#include "asf_meta.h"
#include <stdio.h>
#include <sys/types.h>

#include <glib.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_histogram.h>

// sometimes we don't have this - choose a conservative value
#ifndef SSIZE_MAX
#define SSIZE_MAX 32767
#endif

// Instance structure.  Everything here is private and need not be
// used or understood by client code, except for the size_x and size_y
// fields.
typedef struct {
  size_t size_x, size_y;    // Image dimensions.
  size_t cache_space;       // Memory cache space in bytes.
  size_t cache_area;        // Memory cache area in pixels.
  size_t tile_size;         // Tile size in pixels on a side.
  size_t cache_size_in_tiles;   // Number of tiles in cache.
  size_t tile_count_x;      // Number of tiles in image in x direction.
  size_t tile_count_y;      // Number of tiles in image in y direction.
  size_t tile_count;        // Total number of tiles in image.
  size_t tile_area;         // Area of a tile, in pixels.
  float *cache;             // Memory cache.
  float **tile_addresses;   // Addresss of individual tiles in the cache.
  GQueue *tile_queue;       // Queue of tile offsets kept in load order.
  FILE *tile_file;          // File with tiles stored contiguously.
  GString *tile_file_name;  // Name of the tile file
  int reference_count;      // For optional reference counting.
} FloatImage;

///////////////////////////////////////////////////////////////////////////////
//
// Creating New Instances
//
// Includeing methods which create new instances by copying existing
// ones.
//
///////////////////////////////////////////////////////////////////////////////

// Thaw out a previously frozen instance (produced with
// float_image_freeze) using data pointed to by file_pointer.  Frozen
// instances aren't portable between platforms.  After thawing
// file_pointer points to the data immediately following the data from
// the thawed instance (or to the end of the file).
FloatImage *
float_image_thaw (FILE *file_pointer);

// Create a new image filled with zero pixel values.
FloatImage *
float_image_new (ssize_t size_x, ssize_t size_y);

// Create a new image with pixels initialized to value.
FloatImage *
float_image_new_with_value (ssize_t size_x, ssize_t size_y, float value);

// Create a new image from memory.  This pixels are assumed to be
// layed out in memory in the usual way, i.e. contiguous rows of
// pixels in the x direction are contiguous in memory.
FloatImage *
float_image_new_from_memory (ssize_t size_x, ssize_t size_y, float *buffer);

// Create a new independent copy of model.
FloatImage *
float_image_copy (FloatImage *model);

// Form reduced resolution version of the model.  The scale_factor
// must be positive and odd.  The new image will be round ((double)
// model->size_x / scale_factor) pixels by round ((double)
// model->size_y / scale_factor) pixels.  Scaling is performed by
// averaging blocks of pixels together, using odd pixel reflection
// around the image edges (see the description of the apply_kernel
// method).  The upper and leftmost blocks of pixels averaged together
// are always centered at the 0 index in the direction in question, so
// reflection is always used for these edges.  Whether reflection is
// used for the right and lower edges depends on the relationship
// between the model dimensions and the scale factor.
FloatImage *
float_image_new_from_model_scaled (FloatImage *model, ssize_t scale_factor);

// Create a new image by copying the portion of model with upper left
// corner at model coordinates (x, y), width size_x, and height
// size_y.
FloatImage *
float_image_new_subimage (FloatImage *model, ssize_t x, ssize_t y,
              ssize_t size_x, ssize_t size_y);

// Type used to specify whether disk files should be in big or little
// endian byte order.
typedef enum {
  FLOAT_IMAGE_BYTE_ORDER_LITTLE_ENDIAN=1,
  FLOAT_IMAGE_BYTE_ORDER_BIG_ENDIAN
} float_image_byte_order_t;

// Create a new image from data at byte offset in file.  The pixel
// layout in the file is assumed to be the same as for the
// float_image_new_from_memory method.  The byte order of individual
// pixels in the file should be byte_order.
FloatImage *
float_image_new_from_file (ssize_t size_x, ssize_t size_y, const char *file,
               off_t offset, float_image_byte_order_t byte_order);

// The method is like new_from_file, but takes a file pointer instead
// of a file name, and the offset argument is with respect to the
// current position in the file_pointer stream.
FloatImage *
float_image_new_from_file_pointer (ssize_t size_x, ssize_t size_y,
                   FILE *file_pointer, off_t offset,
                   float_image_byte_order_t byte_order);

// Form a low quality reduced resolution version of the
// original_size_x by original_size_y image in file.  The new image
// will be size_x by size_y pixels.  This method is like new_from_file
// method, but gets its data by sampling in each dimension using
// bilinear interpolation.  This is a decent way of forming quick
// thumbnails of images, or of scaling images down just slightly (by a
// factor of say 1.5 or less), but not much else.
FloatImage *
float_image_new_from_file_scaled (ssize_t size_x, ssize_t size_y,
                  ssize_t original_size_x,
                  ssize_t original_size_y,
                  const char *file, off_t offset,
                  float_image_byte_order_t byte_order);

// The function that does it all, generating an instance of FloatImage
// from a file and the metadata
FloatImage *
float_image_new_from_metadata(meta_parameters *meta, const char *file);

// For multi-band imagery the previous function needs to be more specific.
FloatImage *
float_image_band_new_from_metadata(meta_parameters *meta,
                   int band, const char *file);

// Sample type of an image that is to be used to create a float_image
// instance.  For example, floating point image can be created from
// signed sixteen bit integer data.
typedef enum {
  FLOAT_IMAGE_SAMPLE_TYPE_SIGNED_TWO_BYTE_INTEGER=1,
  FLOAT_IMAGE_SAMPLE_TYPE_UNSIGNED_BYTE
} float_image_sample_type;

// Form a new image by reading a data file full of sample_type
// samples.  The integer sample type are converted to floating point
// values by simple assignment (i.e. C assignment semantics apply,
// which for the smaller integer types should mean than an exact
// floating point representation is possible).  The other arguments
// are like those of the new_from_file method.
FloatImage *
float_image_new_from_file_with_sample_type
  (ssize_t size_x, ssize_t size_y, const char *file, off_t offset,
   float_image_byte_order_t byte_order, float_image_sample_type sample_type);

// This method is to new_from_file_with_sample_type as
// new_from_file_pointer is to new_from_file.
FloatImage *
float_image_new_from_file_pointer_with_sample_type
  (ssize_t size_x, ssize_t size_y, FILE *file_pointer, off_t offset,
   float_image_byte_order_t byte_order, float_image_sample_type sample_type);

///////////////////////////////////////////////////////////////////////////////
//
// Getting and Setting Image Pixels and Regions
//
///////////////////////////////////////////////////////////////////////////////

// Get pixel at 0-indexed position x, y.  A cache is used so pixel
// access does not usually involve the hard disk, provided subsequent
// pixel lookups are spatially close together.  You can probably get
// away with trating this function just as if everything was in
// memory.  For details, see the cache control methods below.
//
// The x and y arguments should always be positive, ssize_t is used
// only so people can't as easily shoot themselves in the foot by
// accidently supplying negative arguments which get promoted in some
// strange way.
float
float_image_get_pixel (FloatImage *self, ssize_t x, ssize_t y);

// Set pixel at 0-indexed position x, y to value.  A cache is used to
// make this fast, as for the float_image_get_pixel method.
void
float_image_set_pixel (FloatImage *self, ssize_t x, ssize_t y, float value);

// Get rectangular image region of size_x, size_y having upper left
// corner at x, y and copy it into already allocated buffer.  There is
// not necessarily any caching help for this method, i.e. it may
// always involve disk access and always be slow.
void
float_image_get_region (FloatImage *self, ssize_t x, ssize_t y,
            ssize_t size_x, ssize_t size_y, float *buffer);

// This method is analogous to float_image_get_region.
void
float_image_set_region (FloatImage *self, size_t x, size_t y, size_t size_x,
            size_t size_y, float *buffer);

// Get a full row of pixels, copying the data into already allocated
// buffer.  This method will be fast on the average for calls with
// sequential row numbers.
void
float_image_get_row (FloatImage *self, size_t row, float *buffer);

// Get a pixel, performing odd reflection at image edges if the pixel
// indicies fall outside the image.  See the description of the
// apply_kernel method for an explanation of reflection.
float
float_image_get_pixel_with_reflection (FloatImage *self, ssize_t x, ssize_t y);

///////////////////////////////////////////////////////////////////////////////
//
// Image Analysis and Statistics
//
///////////////////////////////////////////////////////////////////////////////

// Default mask value when figuring image stats
#define FLOAT_IMAGE_DEFAULT_MASK (0.0)

// Finds the minimum and maximum pixel values in the image, and the
// mean and standard deviation of all pixels.  This function considers
// every pixel in the image when mask is NAN, otherwise it discounts
// all values within .00000000001 of the mask
void
float_image_statistics (FloatImage *self, float *min, float *max, float *mean,
                        float *standard_deviation, float mask);

//  Does the same thing as float_image_statistics() but for only one selected
// band within a multi-band float image.  Returns 1 on error, otherwise 0
int
float_image_band_statistics(FloatImage *self, meta_stats *stats,
                            int line_count, int band_no,
                            float mask);

// This method works like the statistics method, except values in the
// interval [interval_start, interval_end] are not considered at all
// for the purposes of determining any of the outputs.
void
float_image_statistics_with_mask_interval (FloatImage *self, float *min,
                       float *max, float *mean,
                       float *standard_deviation,
                       double interval_start,
                       double interval_end);

// Compute an efficient estimate of the mean and standard deviation of
// the pixels in the image, by sampling every stride th pixel in each
// dimension, beginning with pixel (0, 0). If the mask is a non-NAN
// value, this function will discount all values within .00000000001
// of the mask
void
float_image_approximate_statistics (FloatImage *self, size_t stride,
                                    float *mean, float *standard_deviation,
                                    float mask);

// This method is a logical combination of the
// statistics_with_mask_interval and approximate_statistics methods.
void
float_image_approximate_statistics_with_mask_interval
  (FloatImage *self, size_t stride, float *mean, float *standard_deviation,
   double interval_start, double interval_end);

// Creates a gsl_histogram with 'num_bins' bins evenly spaced between
// 'min' and 'max'.  This function considers every pixel in the image.
gsl_histogram *
float_image_gsl_histogram (FloatImage *self, float min, float max,
                           size_t num_bins);

///////////////////////////////////////////////////////////////////////////////
//
// Kernels, Interpolation, and Sampling
//
///////////////////////////////////////////////////////////////////////////////

// Apply kernel centerd at pixel x, y and return the value.  The
// kernel matrix must be have equal odd dimensions.  The values in the
// kernel are multiplied by the pixels, and the sum of the products
// returned.  When part of the kernel would fall outside the image
// extents, the values used for the out-of-image pixels are the mirror
// images of the corresponding in-image pixels, with the edge pixels
// not duplicated, i.e. reflection about the middle of the edge pixels
// is used.
float
float_image_apply_kernel (FloatImage *self, ssize_t x, ssize_t y,
              gsl_matrix_float *kernel);

// Type used to specify whether disk files should be in big or little
// endian byte order.

// Sample method types.  These dictate how nearby pixels are
// considered when we want to find the approximate value for a point
// which falls between pixel indicies.
typedef enum {
  // Nearest pixel.
  FLOAT_IMAGE_SAMPLE_METHOD_NEAREST_NEIGHBOR,
  // Linearly weited average of four nearest pixels
  FLOAT_IMAGE_SAMPLE_METHOD_BILINEAR,
  // Bicubic spline interpolation (which consideres the nearest 16 pixels).
  FLOAT_IMAGE_SAMPLE_METHOD_BICUBIC
} float_image_sample_method_t;

float
float_image_sample (FloatImage *self, float x, float y,
            float_image_sample_method_t sample_method);

///////////////////////////////////////////////////////////////////////////////
//
// Comparing Images
//
///////////////////////////////////////////////////////////////////////////////

// Return true iff self and other have identical sizes and pixels that
// are all approximately equal to relative accuracy epsilon, as
// understood by the GNU Scientific Library function gsl_fcmp.
gboolean
float_image_equals (FloatImage *self, FloatImage *other, float epsilon);

///////////////////////////////////////////////////////////////////////////////
//
// Manipulating Images
//
///////////////////////////////////////////////////////////////////////////////

// Flip an image about a horizontal line through the center of the image
void
float_image_flip_y(FloatImage *self);

// Flip an image about a vertical line through the center of the image
void
float_image_flip_x(FloatImage *self);

///////////////////////////////////////////////////////////////////////////////
//
// Storing Images in Files
//
///////////////////////////////////////////////////////////////////////////////

// Store instance self at position pointed to by file_pointer, for
// later retrieval using float_image_thaw.  The serialized version of
// self is not portable between platforms.
void
float_image_freeze (FloatImage *self, FILE *file_pointer);

// Store image pixels in file.  The image is stored in the usual
// order, i.e. contiguous rows of pixels in the x direction are stored
// contiguously in memory.  Individual pixels are stored in byte order
// byte_order.  Returns 0 on success, nonzero on error.
int
float_image_store (FloatImage *self, const char *file,
           float_image_byte_order_t byte_order);
int
float_image_store_ext(FloatImage *self, const char *file,
                      float_image_byte_order_t byte_order, int append_flag);

int
float_image_band_store(FloatImage *self, const char *file,
               meta_parameters *meta, int append_flag);

///////////////////////////////////////////////////////////////////////////////
//
// Exporting Images in Various Image File Formats
//
///////////////////////////////////////////////////////////////////////////////

// Export image to file as a gray scaled jpeg image, with largest
// dimension no larger than max_dimension.  The max_dimension argument
// must be less than or equal to the largest dimension of the image.
// The image may be scaled st its largest dimension is considerably
// less than max_dimension.  Scaling is performed by averaging blocks
// of pixels together, using odd pixel reflection around the image
// edges (see the description of the apply_kernel method).  The JPEG
// format uses byte-valued gray scale samples, so the dynamic range of
// gray scale output pixels is limited to [0, 255].  Image pixel
// values inside two standard deviations of the mean pixel value are
// mapped linearly into this range; image pixel values outside two
// standard are clamped at the appropriate limit.  In determining the
// image statistics (mean and standard deviation), values equal to mask
// are not considered, unless mask is NAN, in which case mask has no
// effect.  If all image pixels have the same value, the output is
// made black if the pixels have value 0.0, and white otherwise.  This
// routine slurps the whole image into memory, so beware.  Returns 0
// on success, nonzero on error.
int
float_image_export_as_jpeg (FloatImage *self, const char *file,
                size_t max_dimension, double mask);

// This method works like the export_as_jpeg method, but all values in
// the interval [interval_start, interval_end] are considered to be
// uninteresting low values which should be mapped to zero in the
// output image, and should not be included in the calculations which
// determine the image statistics used to map the other floating point
// values into bytes.  For example, if one has an a bright island
// surrounded by very dark water in a radar image, setting the dark
// water covered areas to zero and not including them in the mean and
// standard deviation calculations will prevent the more interesting
// land areas from being driven into saturation in the generated
// image.
int
float_image_export_as_jpeg_with_mask_interval (FloatImage *self,
                           const char *file,
                           ssize_t max_dimension,
                           double interval_start,
                           double interval_end);

// Export image to file as a gray scaled tiff image, with largest
// dimension no larger than max_dimension.  The max_dimension argument
// must be less than or equal to the largest dimension of the image.
// The image may be scaled st its largest dimension is considerably
// less than max_dimension.  Scaling is performed by averaging blocks
// of pixels together, using odd pixel reflection around the image
// edges (see the description of the apply_kernel method).  The TIFF
// format (here) uses byte-valued gray scale samples, so the dynamic range
// of gray scale output pixels is limited to [0, 255].  Image pixel
// values inside two standard deviations of the mean pixel value are
// mapped linearly into this range; image pixel values outside two
// standard are clamped at the appropriate limit.  In determining the
// image statistics (mean and standard deviation), values equal to mask
// are not considered, unless mask is NAN, in which case mask has no
// effect.  If all image pixels have the same value, the output is
// made black if the pixels have value 0.0, and white otherwise.  This
// routine slurps the whole image into memory, so beware.  Returns 0
// on success, nonzero on error.
int
float_image_export_as_tiff (FloatImage *self, const char *file,
                            size_t max_dimension, double mask);

// This method exports the float image data as an ascii CSV file.
// Don't use this method on large sections of data - it will give
// an assertion failure if either dimension is larger than 255.
int
float_image_export_as_csv (FloatImage *self, const char *file);

///////////////////////////////////////////////////////////////////////////////
//
// Controlling Image Data Caching
//
// It probably isn't necessary to use these methods.  They are
// provided largely to make it clear how the cache works.  The major
// tunable parameter is the size of the in-memory cache to use.
//
// When a new image is created, the following steps are performed:
//
//      1. The image is divided up into square tiles st two full rows
//         or columns of tiles will fit in the memory cache.
//
//      2. A copy of the image is created on disk with the memory
//         layout rearranged st individual tiles are contiguous in
//         memory.  This allows tiles to be quickly retrieved later.
//
// When a pixel is accessed (read or set), the following happens:
//
//      1. If the pixel is in a tile already loaded into the cache,
//         it is simply fetched or set.
//
//      2. Otherwise, the tile containing the pixel is loaded,
//         possibly displacing an already loaded tile, and then the
//         pixel is fetched or set.  The tile displaced is the one
//         loaded longest ago (there is no most-recently-accessed
//         heuristic, as this would make pixel access too slow).
//
// Thus, using a larger memory cache will result in larger tiles being
// used, and fewer tile loads being needed.  In general, the default
// behavior is pretty good, but if you know will be performing lots of
// widely (but not too widely) scattered accesses, you might want to
// make it bigger.
//
///////////////////////////////////////////////////////////////////////////////

// Get the image memory cache size setting, in bytes.  Note that this
// is the memory cache used per image, not the class-wide cache usage.
// If you will have a lot of objects instantiated simultaneously, you
// may find it necessary to use a smaller cache for each image.
size_t
float_image_get_cache_size (FloatImage *self);

// Set the image memory cache to size bytes.  Changing the cache size
// requires the tiling to be recomputed, the on-disk tile cache to be
// regenerated, and the in memory cache to be flushed, so its slow.
void
float_image_set_cache_size (FloatImage *self, size_t size);

///////////////////////////////////////////////////////////////////////////////
//
// Reference Counting or Freeing Instances
//
///////////////////////////////////////////////////////////////////////////////

// Increment reference count.  Return pointer to self for convenience.
FloatImage *
float_image_ref (FloatImage *self);

// Decrement reference count, freeing instance if count falls to 0.
void
float_image_unref (FloatImage *self);

// Destroy self, regardless of reference count.
void
float_image_free (FloatImage *self);

#endif // #ifndef FLOAT_IMAGE_H


/*
 * Copyright (c) 2016-2021 lymastee, All rights reserved.
 * Contact: lymastee@hotmail.com
 *
 * This file is part of the gslib project.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#pragma once

#ifndef mesh_7c5c4ae5_0f3e_4a2d_936e_0447239ac3a7_h
#define mesh_7c5c4ae5_0f3e_4a2d_936e_0447239ac3a7_h

#include <gslib/type.h>
#include <gslib/std.h>
#include <ariel/type.h>

__ariel_begin__

struct mesh_uv_set;
struct mesh_tangent_set;

typedef vector<vec3> mesh_points;
typedef vector<vec3> mesh_normals;
typedef vector<vec3> mesh_tangents;
typedef vector<vec3> mesh_colors;
typedef vector<vec2> mesh_uv_coords;
typedef vector<int32> mesh_faces;
typedef vector<mesh_uv_set> mesh_uv_sets;
typedef vector<mesh_tangent_set> mesh_tangent_sets;

struct mesh_uv_set
{
    string              name;
    mesh_uv_coords      coords;
};

struct mesh_tangent_set
{
    string              name;
    mesh_tangents       tangents;
};

class mesh:
    public res_node
{
    friend class mesh_io;

public:
    mesh();
    virtual ~mesh() {}
    virtual res_type get_type() const override { return res_mesh; }
    bool has_indices() const { return !_faces.empty(); }
    bool has_points() const { return !_points.empty(); }
    bool has_normals() const { return !_normals.empty(); }
    bool has_colors() const { return !_vcolors.empty(); }
    bool has_uvs() const { return !_uvsets.empty(); }
    bool has_tangents() const { return !_tangentsets.empty(); }
    int32 num_uv_sets() const { return (int32)_uvsets.size(); }
    int32 num_tangent_sets() const { return (int32)_tangentsets.size(); }
    int32 num_points() const { return (int32)_points.size(); }
    int32 num_indices() const { return (int32)_faces.size(); }
    const mesh_points& get_const_points() const { return _points; }
    const mesh_faces& get_const_indices() const { return _faces; }
    const mesh_normals& get_const_normals() const { return _normals; }
    const mesh_colors& get_const_colors() const { return _vcolors; }

protected:
    mesh_points         _points;
    mesh_normals        _normals;
    mesh_colors         _vcolors;
    mesh_uv_sets        _uvsets;
    mesh_tangent_sets   _tangentsets;
    mesh_faces          _faces;
    matrix              _transforms;

public:
    /*
     * Caution:
     * If there were splited vertices in the mesh, the normals & tangents could be incorrect,
     * in such situations, you should always trust the data from exporter.
     */
    void calc_normals();
};

__ariel_end__

#endif


/* vector/gsl_vector_complex_float.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_VECTOR_COMPLEX_FLOAT_H__
#define __GSL_VECTOR_COMPLEX_FLOAT_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_float.h>
#include <gsl/gsl_vector_complex.h>
#include <gsl/gsl_block_complex_float.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct
{
  size_t size;
  size_t stride;
  float *data;
  gsl_block_complex_float *block;
  int owner;
} gsl_vector_complex_float;

typedef struct
{
  gsl_vector_complex_float vector;
} _gsl_vector_complex_float_view;

typedef _gsl_vector_complex_float_view gsl_vector_complex_float_view;

typedef struct
{
  gsl_vector_complex_float vector;
} _gsl_vector_complex_float_const_view;

typedef const _gsl_vector_complex_float_const_view gsl_vector_complex_float_const_view;

/* Allocation */

GSL_FUN gsl_vector_complex_float *gsl_vector_complex_float_alloc (const size_t n);
GSL_FUN gsl_vector_complex_float *gsl_vector_complex_float_calloc (const size_t n);

GSL_FUN gsl_vector_complex_float *
gsl_vector_complex_float_alloc_from_block (gsl_block_complex_float * b,
                                           const size_t offset,
                                           const size_t n,
                                           const size_t stride);

GSL_FUN gsl_vector_complex_float *
gsl_vector_complex_float_alloc_from_vector (gsl_vector_complex_float * v,
                                             const size_t offset,
                                             const size_t n,
                                             const size_t stride);

GSL_FUN void gsl_vector_complex_float_free (gsl_vector_complex_float * v);

/* Views */

GSL_FUN _gsl_vector_complex_float_view
gsl_vector_complex_float_view_array (float *base,
                                     size_t n);

GSL_FUN _gsl_vector_complex_float_view
gsl_vector_complex_float_view_array_with_stride (float *base,
                                                 size_t stride,
                                                 size_t n);

GSL_FUN _gsl_vector_complex_float_const_view
gsl_vector_complex_float_const_view_array (const float *base,
                                           size_t n);

GSL_FUN _gsl_vector_complex_float_const_view
gsl_vector_complex_float_const_view_array_with_stride (const float *base,
                                                       size_t stride,
                                                       size_t n);

GSL_FUN _gsl_vector_complex_float_view
gsl_vector_complex_float_subvector (gsl_vector_complex_float *base,
                                         size_t i,
                                         size_t n);

GSL_FUN _gsl_vector_complex_float_view
gsl_vector_complex_float_subvector_with_stride (gsl_vector_complex_float *v,
                                                size_t i,
                                                size_t stride,
                                                size_t n);

GSL_FUN _gsl_vector_complex_float_const_view
gsl_vector_complex_float_const_subvector (const gsl_vector_complex_float *base,
                                               size_t i,
                                               size_t n);

GSL_FUN _gsl_vector_complex_float_const_view
gsl_vector_complex_float_const_subvector_with_stride (const gsl_vector_complex_float *v,
                                                      size_t i,
                                                      size_t stride,
                                                      size_t n);

GSL_FUN _gsl_vector_float_view
gsl_vector_complex_float_real (gsl_vector_complex_float *v);

GSL_FUN _gsl_vector_float_view
gsl_vector_complex_float_imag (gsl_vector_complex_float *v);

GSL_FUN _gsl_vector_float_const_view
gsl_vector_complex_float_const_real (const gsl_vector_complex_float *v);

GSL_FUN _gsl_vector_float_const_view
gsl_vector_complex_float_const_imag (const gsl_vector_complex_float *v);

/* Operations */

GSL_FUN void gsl_vector_complex_float_set_zero (gsl_vector_complex_float * v);
GSL_FUN void gsl_vector_complex_float_set_all (gsl_vector_complex_float * v,
                                       gsl_complex_float z);
GSL_FUN int gsl_vector_complex_float_set_basis (gsl_vector_complex_float * v, size_t i);

GSL_FUN int gsl_vector_complex_float_fread (FILE * stream,
                                    gsl_vector_complex_float * v);
GSL_FUN int gsl_vector_complex_float_fwrite (FILE * stream,
                                     const gsl_vector_complex_float * v);
GSL_FUN int gsl_vector_complex_float_fscanf (FILE * stream,
                                     gsl_vector_complex_float * v);
GSL_FUN int gsl_vector_complex_float_fprintf (FILE * stream,
                                      const gsl_vector_complex_float * v,
                                      const char *format);

GSL_FUN int gsl_vector_complex_float_memcpy (gsl_vector_complex_float * dest, const gsl_vector_complex_float * src);

GSL_FUN int gsl_vector_complex_float_reverse (gsl_vector_complex_float * v);

GSL_FUN int gsl_vector_complex_float_swap (gsl_vector_complex_float * v, gsl_vector_complex_float * w);
GSL_FUN int gsl_vector_complex_float_swap_elements (gsl_vector_complex_float * v, const size_t i, const size_t j);

GSL_FUN int gsl_vector_complex_float_equal (const gsl_vector_complex_float * u,
                                    const gsl_vector_complex_float * v);

GSL_FUN int gsl_vector_complex_float_isnull (const gsl_vector_complex_float * v);
GSL_FUN int gsl_vector_complex_float_ispos (const gsl_vector_complex_float * v);
GSL_FUN int gsl_vector_complex_float_isneg (const gsl_vector_complex_float * v);
GSL_FUN int gsl_vector_complex_float_isnonneg (const gsl_vector_complex_float * v);

GSL_FUN int gsl_vector_complex_float_add (gsl_vector_complex_float * a, const gsl_vector_complex_float * b);
GSL_FUN int gsl_vector_complex_float_sub (gsl_vector_complex_float * a, const gsl_vector_complex_float * b);
GSL_FUN int gsl_vector_complex_float_mul (gsl_vector_complex_float * a, const gsl_vector_complex_float * b);
GSL_FUN int gsl_vector_complex_float_div (gsl_vector_complex_float * a, const gsl_vector_complex_float * b);
GSL_FUN int gsl_vector_complex_float_scale (gsl_vector_complex_float * a, const gsl_complex_float x);
GSL_FUN int gsl_vector_complex_float_add_constant (gsl_vector_complex_float * a, const gsl_complex_float x);
GSL_FUN int gsl_vector_complex_float_axpby (const gsl_complex_float alpha, const gsl_vector_complex_float * x, const gsl_complex_float beta, gsl_vector_complex_float * y);

GSL_FUN INLINE_DECL gsl_complex_float gsl_vector_complex_float_get (const gsl_vector_complex_float * v, const size_t i);
GSL_FUN INLINE_DECL void gsl_vector_complex_float_set (gsl_vector_complex_float * v, const size_t i, gsl_complex_float z);
GSL_FUN INLINE_DECL gsl_complex_float *gsl_vector_complex_float_ptr (gsl_vector_complex_float * v, const size_t i);
GSL_FUN INLINE_DECL const gsl_complex_float *gsl_vector_complex_float_const_ptr (const gsl_vector_complex_float * v, const size_t i);

#ifdef HAVE_INLINE

INLINE_FUN
gsl_complex_float
gsl_vector_complex_float_get (const gsl_vector_complex_float * v,
                              const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      gsl_complex_float zero = {{0, 0}};
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, zero);
    }
#endif
  return *GSL_COMPLEX_FLOAT_AT (v, i);
}

INLINE_FUN
void
gsl_vector_complex_float_set (gsl_vector_complex_float * v,
                              const size_t i, gsl_complex_float z)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VOID ("index out of range", GSL_EINVAL);
    }
#endif
  *GSL_COMPLEX_FLOAT_AT (v, i) = z;
}

INLINE_FUN
gsl_complex_float *
gsl_vector_complex_float_ptr (gsl_vector_complex_float * v,
                              const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return GSL_COMPLEX_FLOAT_AT (v, i);
}

INLINE_FUN
const gsl_complex_float *
gsl_vector_complex_float_const_ptr (const gsl_vector_complex_float * v,
                                    const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return GSL_COMPLEX_FLOAT_AT (v, i);
}

#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_VECTOR_COMPLEX_FLOAT_H__ */


/*
We are using the OpenCV implementation and adding gridding to the
feature detection.

Modified : computeKeyPoints
Added methods : keepBestKeyPoints and subimageToImageCoordinates
*/

/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2009, Willow Garage, Inc.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Willow Garage nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/** Authors: Ethan Rublee, Vincent Rabaud, Gary Bradski */

#pragma once

#include "Utils\thread_memory.h"
#include "ImageData.h"

#include <iterator>

#include <opencv2\core\types.hpp>

#include <gsl\gsl>

namespace UnitTests
{
    class OpenCVModifiedUnitTest;
    class OrbFeatureDetectorUnitTest;
}

class OrbDetector
{
    using ImageData = mage::ImageData<mage::ImageAllocator>;
public:
    OrbDetector(
        unsigned int gaussianKernelSize,
        unsigned int nfeatures,
        float scaleFactor,
        unsigned int nlevels,
        unsigned int patchSize,
        unsigned int fastThreshold,
        bool useOrientation,
        float featureFactorANMS,
        float featureStrengthANMS,
        int strongResponseANMS,
        float minRobustFactor,
        float maxRobustFactor,
        int numCellsX,
        int numCellsY);

    // Compute the ORB_Impl features and descriptors on an image
    void DetectAndCompute(
        mage::thread_memory memory,
        ImageData& imageData,
        const cv::Mat& image);
private:

    void ComputeKeyPoints(const cv::Mat& imagePyramid,
        gsl::span<const cv::Rect> layerInfo,
        gsl::span<const float> layerScale,
        mage::thread_memory memory,
        ImageData& result);

    static void ResizeAndComputeOrbDescriptorsPrerotated(
        const cv::Mat& image,
        gsl::span<const cv::KeyPoint> keypoints,
        gsl::span<mage::ORBDescriptor> descriptors,
        const std::vector<std::vector<signed char>>& scaledPatterns,
        size_t dsize,
        float upScale);    // amount to upscale the source image

    static void ComputeOrbDescriptorsPrerotated(
        const cv::Mat& imagePyramid,
        gsl::span<const cv::Rect> layerInfo,
        gsl::span<const float> layerScale,
        gsl::span<const cv::KeyPoint> keypoints,
        gsl::span<mage::ORBDescriptor> descriptors,
        const signed char* _patternRotated,
        size_t dsize);

    static void ComputeOrbDescriptors(
        const cv::Mat& imagePyramid,
        gsl::span<const cv::Rect> layerInfo,
        gsl::span<const float> layerScale,
        gsl::span<const cv::KeyPoint> keypoints,
        gsl::span<mage::ORBDescriptor> descriptors,
        gsl::span<const cv::Point> _pattern,
        size_t dsize);

    static void ICAngles(
        const cv::Mat& img,
        gsl::span<const cv::Rect> layerinfo,
        gsl::span<const int> u_max,
        int half_k,
        gsl::span<cv::KeyPoint> pts);

    static void HarrisResponses(
        const cv::Mat& img,
        gsl::span<const cv::Rect> layerinfo,
        gsl::span<cv::KeyPoint> pts,
        int blockSize,
        float harris_k);

    static void MakeRandomPattern(int patchSize, cv::Point* pattern, int npoints);

    enum class FeatureType
    {
        TYPE_5_8 = 0, TYPE_7_12 = 1, TYPE_9_16 = 2
    };

    void AdaptiveNonMaximalSuppresion(mage::temp::vector<cv::KeyPoint>& keypoints,
        unsigned int numToKeep, int threshold, mage::thread_memory memory);
    void FAST(
        const cv::Mat& img,
        mage::temp::vector<cv::KeyPoint>& keypoints,
        int threshold,
        bool nonmax_suppression,
        uchar* threshold_tab,
        mage::thread_memory& memory,
        FeatureType type = FeatureType::TYPE_9_16);

    const unsigned int m_gaussianKernelSize;
    const unsigned int m_nfeatures;
    const float m_scaleFactor;
    const unsigned int m_nlevels;
    const unsigned int m_patchSize;
    const unsigned int m_fastThreshold;
    const bool m_useOrientation;
    const float m_featureFactorANMS;
    const float m_featureStrengthANMS;
    const int m_strongResponseANMS;
    const float m_minRobustFactorANMS;
    const float m_maxRobustFactorANMS;
    const int m_numCellsX;
    const int m_numCellsY;

    friend class ::UnitTests::OpenCVModifiedUnitTest;
    friend class ::UnitTests::OrbFeatureDetectorUnitTest;
};


#pragma once
#include <map>
#include <vector>
#ifndef _NOGSL
#include <gsl/gsl_vector.h>
#include <gsl/gsl_blas.h>
#else
#include "FakeGSL.h"
#endif
#include "BooleanNodes.h"
#include "CommandLineArgs.h"

class Util {
public:
	static map<int, int> getNodeToValMap(map<int, int>& inputMap, vector<int>& inputs) {
		map<int, int> res;
		for(auto i = 0; i < inputs.size(); i++) {
			if (inputs[i] == 0 || inputs[i] == 1) {
				res[inputMap[i]] = inputs[i];
			}
		}
		return res;
	}

    static bool isAbsolute(bool_node* n) {
        if (n->type != bool_node::LT) {
            return false;
        }
        bool_node* v;
        if (n->mother()->type == bool_node::CONST && ((CONST_node*) (n->mother()))->getFval() == 0) {
            v = n->father();
        } else if (n->father()->type == bool_node::CONST && ((CONST_node*) (n->father()))->getFval() == 0) {
            v = n->mother();
        } else {
            return false;
        }
        FastSet<bool_node>& children = n->children;
        if (children.size() > 1) return false;
        for(child_iter it = children.begin(); it != children.end(); ++it) {
            if ((*it)->type == bool_node::ARRACC) {
                ARRACC_node* ac = (ARRACC_node*)(*it);
                if (ac->mother() != n) {
                    return false;
                }
                bool_node* m = ac->arguments(0);
                bool_node* f = ac->arguments(1);
                if (m != v && f != v) {
                    return false;
                }
                if (m == v) {
                    if (f->type != bool_node::NEG || f->mother() != v) {
                        return false;
                    }
                }
                if (f == v) {
                    if (m->type != bool_node::NEG || m->mother() != v) {
                        return false;
                    }
                }
            } else {
                return false;
            }
        }
        cout << "Absolute node: " << n->lprint() << endl;
        return true;
    }

    static bool isSqrt(bool_node* n) {
        if (n->type != bool_node::UFUN) {
            return false;
        }
        UFUN_node* un = (UFUN_node*) n;
        if (un->get_ufname() == "sqrt_math") {
            return true;
        }
        return false;
    }

    static bool hasArraccChild(bool_node* n) {
        FastSet<bool_node>& children = n->children;
        for(child_iter it = children.begin(); it != children.end(); ++it) {
            if ((*it)->type == bool_node::ARRACC && (*it)->mother() == n) {
                return true;
            }
        }
        return false;
    }

    static bool hasAssertChild(bool_node& n) {
        FastSet<bool_node>& children = n.children;
        if (children.size() > 1) return false;
        for(child_iter it = children.begin(); it != children.end(); ++it) {
            if ((*it)->type == bool_node::ASSERT) {
                return true;
            }
        }
        return false;
    }

    static bool hasNotAssertChild(bool_node& n) {
        FastSet<bool_node>& children = n.children;
        if (children.size() > 1) return false;
        for(child_iter it = children.begin(); it != children.end(); ++it) {
            if ((*it)->type == bool_node::NOT) {
                FastSet<bool_node>& grandChildren = (*it)->children;
                if (grandChildren.size() > 1) return false;
                for (child_iter it1 = grandChildren.begin(); it1 != grandChildren.end(); ++it1) {
                    if ((*it1)->type == bool_node::ASSERT) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    static bool hasAssertChild(bool_node* n) {
        return hasAssertChild(*n);
    }

    static bool hasNotAssertChild(bool_node* n) {
        return hasNotAssertChild(*n);
    }

    static set<int> getRelevantNodes(bool_node* n) {
        set<int> ids;
        set<int> visitedIds;
        vector<bool_node*> toVisit;
        toVisit.push_back(n);

        while(toVisit.size() > 0) {
            bool_node* node = toVisit.back();
            toVisit.pop_back();
            if (visitedIds.find(node->id) == visitedIds.end()) {
                visitedIds.insert(node->id);
                ids.insert(node->id);

				for (auto it = node->p_begin(); it != node->p_end(); ++it) {
                    toVisit.push_back(*it);
                }
            }
        }
        return ids;
    }

    static string print(const gsl_vector* v) {
        stringstream s;
        for (int i = 0; i < v->size; i++) {
            s << gsl_vector_get(v, i) << ";";
        }
        return s.str();
    }
    static string print(const gsl_vector* v, string delimiter) {
        stringstream s;
        for (int i = 0; i < v->size; i++) {
            s << gsl_vector_get(v, i) << delimiter;
        }
        return s.str();
    }

    static string print(double* arr, int len) {
        stringstream s;
        for (int i = 0; i < len; i++) {
            s << arr[i] << ";";
        }
        return s.str();
    }

    static string print(const vector<int>& v) {
        stringstream s;
        for (auto it = v.begin(); it != v.end(); it++) {
            s << *it << ";";
        }
        return s.str();
    }

    static string print(const vector<double>& v) {
        stringstream s;
        for (auto it = v.begin(); it != v.end(); it++) {
            s << *it << ";";
        }
        return s.str();
    }

    static string print(const set<int>& v) {
        stringstream s;
        for (auto it = v.begin(); it != v.end(); it++) {
            s << *it << ";";
        }
        return s.str();
    }

    static double getMin(const vector<double>& vals) {
        double minval = 1e30;
        for (int i = 0; i < vals.size(); i++) {
            if (vals[i] < minval) {
                minval = vals[i];
            }
        }
        return minval;
    }

    static double norm(const gsl_vector* v) {
        return gsl_blas_dnrm2(v);
    }

    static bool sameDir(const gsl_vector* v1, const gsl_vector* v2) {
        double dp = 0.0;
        gsl_blas_ddot(v1, v2, &dp);
        dp = dp/(norm(v1) * norm(v2));
        //cout << "dot product: " << dp << endl;
        if (dp > 0.9) return true;
        return false;
    }

    static string benchName() {
        string s = PARAMS->inputFname;
        int x1 = s.rfind(".sk");
        int x2 = s.rfind("/tmp/");
        return s.substr(x2+5, x1-x2 - 5);

    }

    static vector<string> split(string &text, string sep) {
        vector<string> tokens;
        size_t start = 0, end = 0;
        while ((end = text.find(sep, start)) != string::npos) {
            tokens.push_back(text.substr(start, end - start));
            start = end + 1;
        }
        tokens.push_back(text.substr(start));
        return tokens;
    }

};


/* multifit/work.c
 *
 * Copyright (C) 2000 Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_multifit.h>

gsl_multifit_linear_workspace *
gsl_multifit_linear_alloc (size_t n, size_t p)
{
  gsl_multifit_linear_workspace *w;

  w = (gsl_multifit_linear_workspace *)
    malloc (sizeof (gsl_multifit_linear_workspace));

  if (w == 0)
    {
      GSL_ERROR_VAL ("failed to allocate space for multifit_linear struct",
                     GSL_ENOMEM, 0);
    }

  w->n = n;                     /* number of observations */
  w->p = p;                     /* number of parameters */

  w->A = gsl_matrix_alloc (n, p);

  if (w->A == 0)
    {
      free (w);
      GSL_ERROR_VAL ("failed to allocate space for A", GSL_ENOMEM, 0);
    }

  w->Q = gsl_matrix_alloc (p, p);

  if (w->Q == 0)
    {
      gsl_matrix_free (w->A);
      free (w);
      GSL_ERROR_VAL ("failed to allocate space for Q", GSL_ENOMEM, 0);
    }

  w->QSI = gsl_matrix_alloc (p, p);

  if (w->QSI == 0)
    {
      gsl_matrix_free (w->Q);
      gsl_matrix_free (w->A);
      free (w);
      GSL_ERROR_VAL ("failed to allocate space for QSI", GSL_ENOMEM, 0);
    }

  w->S = gsl_vector_alloc (p);

  if (w->S == 0)
    {
      gsl_matrix_free (w->QSI);
      gsl_matrix_free (w->Q);
      gsl_matrix_free (w->A);
      free (w);
      GSL_ERROR_VAL ("failed to allocate space for S", GSL_ENOMEM, 0);
    }

  w->t = gsl_vector_alloc (n);

  if (w->t == 0)
    {
      gsl_vector_free (w->S);
      gsl_matrix_free (w->QSI);
      gsl_matrix_free (w->Q);
      gsl_matrix_free (w->A);
      free (w);
      GSL_ERROR_VAL ("failed to allocate space for t", GSL_ENOMEM, 0);
    }

  w->xt = gsl_vector_calloc (p);

  if (w->xt == 0)
    {
      gsl_vector_free (w->t);
      gsl_vector_free (w->S);
      gsl_matrix_free (w->QSI);
      gsl_matrix_free (w->Q);
      gsl_matrix_free (w->A);
      free (w);
      GSL_ERROR_VAL ("failed to allocate space for xt", GSL_ENOMEM, 0);
    }

  w->D = gsl_vector_calloc (p);

  if (w->D == 0)
    {
      gsl_vector_free (w->D);
      gsl_vector_free (w->t);
      gsl_vector_free (w->S);
      gsl_matrix_free (w->QSI);
      gsl_matrix_free (w->Q);
      gsl_matrix_free (w->A);
      free (w);
      GSL_ERROR_VAL ("failed to allocate space for xt", GSL_ENOMEM, 0);
    }

  return w;
}

void
gsl_multifit_linear_free (gsl_multifit_linear_workspace * work)
{
  gsl_matrix_free (work->A);
  gsl_matrix_free (work->Q);
  gsl_matrix_free (work->QSI);
  gsl_vector_free (work->S);
  gsl_vector_free (work->t);
  gsl_vector_free (work->xt);
  gsl_vector_free (work->D);
  free (work);
}


#ifdef ESL_WITH_GSL
/* interface_gsl.h
 * Easel's interfaces to the GNU Scientific Library
 *
 * SRE, Tue Jul 13 15:36:48 2004
 * SVN $Id: interface_gsl.h 11 2005-01-06 11:44:17Z eddy $
 */
#ifndef ESL_INTERFACE_GSL_INCLUDED
#define ESL_INTERFACE_GSL_INCLUDED

#include <stdlib.h>
#include <easel/easel.h>
#include <easel/dmatrix.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_permutation.h>
#include <gsl/gsl_eigen.h>

extern int esl_GSL_MatrixInversion(ESL_DMATRIX *A, ESL_DMATRIX **ret_Ai);

#endif /*ESL_INTERFACE_GSL_INCLUDED*/
#endif /*ESL_WITH_GSL*/


#ifndef BRATU3D_H
#define BRATU3D_H

#include <petsc.h>

typedef struct Params {
  double lambda_;
} Params;

PetscErrorCode FormInitGuess(DM da, Vec x, Params *p);
PetscErrorCode FormFunction(DM da, Vec x, Vec F, Params *p);
PetscErrorCode FormJacobian(DM da, Vec x, Mat J, Params *p);

#endif/*BRATU3D_H*/


/* ode-initval/odeiv.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/* Author:  G. Jungman
 */
#include <config.h>
#include <stdlib.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_odeiv2.h>

gsl_odeiv2_step *
gsl_odeiv2_step_alloc (const gsl_odeiv2_step_type * T, size_t dim)
{
  gsl_odeiv2_step *s = (gsl_odeiv2_step *) malloc (sizeof (gsl_odeiv2_step));

  if (s == 0)
    {
      GSL_ERROR_NULL ("failed to allocate space for ode struct", GSL_ENOMEM);
    };

  s->type = T;
  s->dimension = dim;

  s->state = s->type->alloc (dim);

  if (s->state == 0)
    {
      free (s);                 /* exception in constructor, avoid memory leak */

      GSL_ERROR_NULL ("failed to allocate space for ode state", GSL_ENOMEM);
    };

  return s;
}

const char *
gsl_odeiv2_step_name (const gsl_odeiv2_step * s)
{
  return s->type->name;
}

unsigned int
gsl_odeiv2_step_order (const gsl_odeiv2_step * s)
{
  return s->type->order (s->state);
}

int
gsl_odeiv2_step_apply (gsl_odeiv2_step * s,
                       double t,
                       double h,
                       double y[],
                       double yerr[],
                       const double dydt_in[],
                       double dydt_out[], const gsl_odeiv2_system * dydt)
{
  return s->type->apply (s->state, s->dimension, t, h, y, yerr, dydt_in,
                         dydt_out, dydt);
}

int
gsl_odeiv2_step_reset (gsl_odeiv2_step * s)
{
  return s->type->reset (s->state, s->dimension);
}

void
gsl_odeiv2_step_free (gsl_odeiv2_step * s)
{
  RETURN_IF_NULL (s);
  s->type->free (s->state);
  free (s);
}

int
gsl_odeiv2_step_set_driver (gsl_odeiv2_step * s, const gsl_odeiv2_driver * d)
{
  if (d != NULL)
    {
      s->type->set_driver (s->state, d);
    }
  else
    {
      GSL_ERROR ("driver pointer is null", GSL_EFAULT);
    }

  return GSL_SUCCESS;
}


#pragma once
#include <fstream>
#include <memory>
#include <optional>
#include <sstream>
#include <utility>

#include <gsl/pointers>

#include <fmt/core.h>
#include <fmt/ranges.h>

#include <nop/serializer.h>
#include <nop/status.h>
#include <nop/structure.h>
#include <nop/utility/die.h>
#include <nop/utility/stream_reader.h>
#include <nop/utility/stream_writer.h>

#include <core/Util.h>
#include <core/storage/Page.h>
#include <core/storage/PageCache.h>
#include <core/storage/btree/Config.h>
#include <core/storage/btree/Node.h>

namespace internal::storage::btree {

namespace util {
template<BtreeConfig Config = DefaultConfig>
class BtreePrinter;
}

template<BtreeConfig Config = DefaultConfig>
class Btree final {
	using Self = Btree<Config>;

	using Key = typename Config::Key;
	using Val = typename Config::Val;
	using Ref = typename Config::Ref;
	using Nod = Node<Config>;

	friend util::BtreePrinter<Config>;

public:
	//! Number of entries in branch and leaf nodes may differ
	//! Directly unwrap with `.value()` since we _want to fail at compile time_ in case their is no value which
	//! satisfies the predicates
	int NUM_LINKS_BRANCH = ::internal::binsearch_primitive(2l, Page::size(), [](long current, long, long)
			{ return nop::Encoding<Nod>::Size({typename Nod::Metadata(typename Nod::Branch(std::vector<Ref>(current), std::vector<Position>(current))), {}, true}) - Page::size(); }).value();
	int NUM_RECORDS_BRANCH = NUM_LINKS_BRANCH - 1;

	//! Equivalent to `m` in Knuth's definition
	//! Make sure that when a leaf is split, its contents could be distributed among the two branch nodes.
	//! Directly unwrap with `.value()` since we _want to fail at compile time_ in case their is no value which
	//! satisfies the predicates
	int _NUM_RECORDS_LEAF = ::internal::binsearch_primitive(2l, Page::size(), [](long current, long, long)
			{ return nop::Encoding<Nod>::Size({typename Nod::Metadata(typename Nod::Leaf(std::vector<Key>(current), std::vector<Val>(current))), {}, true}) - Page::size(); }).value();
	int NUM_RECORDS_LEAF = _NUM_RECORDS_LEAF - 1 >= NUM_RECORDS_BRANCH * 2
	        ? NUM_RECORDS_BRANCH * 2 - 1
	        : _NUM_RECORDS_LEAF;

private:
	static inline constexpr bool APPLY_COMPRESSION = Config::APPLY_COMPRESSION;
	static inline constexpr int PAGE_CACHE_SIZE = Config::PAGE_CACHE_SIZE;

	static inline constexpr uint32_t MAGIC = 0xB75EEA41;

public:
	struct Header {
		Position m_rootpos;
		std::size_t m_size{};
		std::size_t m_depth{};
		uint32_t m_magic{MAGIC};
		uint32_t m_pgcache_size{PAGE_CACHE_SIZE};
		uint8_t m_apply_compression{APPLY_COMPRESSION};

		/*
		 * The storage locations of the tree header and the tree contents differ.
		 * This one stores the name of the file which contains the header of the tree,
		 * whereas the other name passed to the Btree constructor is the one where
		 * the actual nodes of the tree are stored.
		 */
		std::string m_content_file;

		/*
		 * We don't want to serialize this. It is used only to check whether the header
		 * we are currently possessing is valid.
		 */
		bool m_dirty{false};

		Header() = default;
		explicit Header(Position rootpos, std::size_t size, std::size_t depth, std::string_view content_file)
		    : m_rootpos{rootpos},
		      m_size{size},
		      m_depth{depth},
		      m_content_file{std::string{content_file}} {}

		[[nodiscard]] auto &rootpos() noexcept { return m_rootpos; }

		[[nodiscard]] auto &size() noexcept { return m_size; }

		[[nodiscard]] auto &depth() noexcept { return m_depth; }

		[[nodiscard]] auto &dirty() noexcept { return m_dirty; }

		auto operator<=>(const Header &) const noexcept = default;

		friend std::ostream &operator<<(std::ostream &os, const Header &h) {
			os << "Header { .rootpos = " << h.m_rootpos << ", .size =" << h.m_size << ", .depth =" << h.m_depth << " }";
			return os;
		}

		NOP_STRUCTURE(Header, m_rootpos, m_size, m_depth, m_magic, m_pgcache_size, m_apply_compression, m_content_file);
	};

private:
	[[nodiscard]] bool is_node_full(const Self::Nod &node) {
		if (node.is_branch())
			return node.is_full(NUM_RECORDS_BRANCH);
		return node.is_full(NUM_RECORDS_LEAF);
	}

	[[nodiscard]] auto node_split(Self::Nod &node) {
		if (node.is_branch())
			return node.split(NUM_RECORDS_BRANCH);
		return node.split(NUM_RECORDS_LEAF);
	}

	[[nodiscard]] std::optional<Val> search_subtree(const Self::Nod &node, const Self::Key &target_key) const noexcept {
		if (node.is_branch()) {
			const auto &refs = node.branch().m_refs;
			const std::size_t index = std::lower_bound(refs.cbegin(), refs.cend(), target_key) - refs.cbegin();
			const Position pos = node.branch().m_links[index];
			const auto other = Nod::from_page(m_pgcache.get_page(pos));
			return search_subtree(other, target_key);
		}
		assert(node.is_leaf());

		const auto &keys = node.leaf().m_keys;
		const auto &vals = node.leaf().m_vals;
		const auto it = std::lower_bound(keys.cbegin(), keys.cend(), target_key);
		if (it == keys.cend() || *it != target_key)
			return {};
		return vals[it - keys.cbegin()];
	}

	Nod make_new_root() {
		auto old_root = root();
		auto old_pos = m_rootpos;

		auto new_pos = m_pgcache.get_new_pos();

		old_root.set_parent(new_pos);
		old_root.set_root(false);

		auto [midkey, sibling] = node_split(old_root);
		auto sibling_pos = m_pgcache.get_new_pos();

		Nod new_root{typename Nod::Metadata(typename Nod::Branch({midkey}, {old_pos, sibling_pos})), new_pos, true};

		m_pgcache.put_page(new_pos, new_root.make_page());
		m_pgcache.put_page(old_pos, old_root.make_page());
		m_pgcache.put_page(sibling_pos, sibling.make_page());

		m_rootpos = new_pos;
		++m_depth;
		m_header.m_dirty = true;

		return new_root;
	}

public:
	[[nodiscard]] auto root() noexcept { return std::as_const(*this).root(); }

	[[nodiscard]] auto root() const noexcept { return Nod::from_page(m_pgcache.get_page(rootpos())); }

	[[nodiscard]] auto &header() noexcept { return m_header; }

	[[nodiscard]] const auto &rootpos() const noexcept { return m_rootpos; }

	[[nodiscard]] std::size_t size() noexcept { return m_size; }

	[[nodiscard]] std::size_t size() const noexcept { return m_size; }

	[[nodiscard]] bool empty() const noexcept { return size() == 0; }

	[[nodiscard]] bool empty() noexcept { return size() == 0; }

	[[nodiscard]] std::size_t depth() { return m_depth; }

	[[nodiscard]] auto num_records_leaf() const noexcept { return NUM_RECORDS_LEAF; }

	[[nodiscard]] auto num_records_branch() const noexcept { return NUM_RECORDS_BRANCH; }

public:
	/*
	 *  Operations API
	 */

	void put(const Self::Key &key, const Self::Val &val) {
		Position currpos{rootpos()};
		Nod curr{root()};

		if (is_node_full(curr))
			curr = make_new_root();

		while (true) {
			if (curr.is_leaf()) {
				/* fmt::print(" -- Putting kv pair in leaf ... \n"); */
				auto &keys = curr.leaf().m_keys;
				auto &vals = curr.leaf().m_vals;

				const std::size_t index = std::lower_bound(keys.cbegin(), keys.cend(), key) - keys.cbegin();
				if (!keys.empty() && index < keys.size() && keys[index] == key)
					return;

				keys.insert(keys.begin() + index, key);
				vals.insert(vals.begin() + index, val);
				m_pgcache.put_page(currpos, curr.make_page());
				++m_size;
				break;
			}

			auto &refs = curr.branch().m_refs;
			auto &links = curr.branch().m_links;

			const std::size_t index = std::lower_bound(refs.cbegin(), refs.cend(), key) - refs.cbegin();
			const Position child_pos = links[index];
			assert(child_pos.is_set());
			auto child = Nod::from_page(m_pgcache.get_page(child_pos));

			if (!is_node_full(child)) {
				currpos = child_pos;
				curr = std::move(child);
				continue;
			}

			auto [midkey, sibling] = node_split(child);
			auto sibling_pos = m_pgcache.get_new_pos();

			assert(std::find(refs.cbegin(), refs.cend(), midkey) == refs.cend());
			assert(std::find(links.cbegin(), links.cend(), sibling_pos) == links.cend());

			refs.insert(refs.begin() + index, midkey);
			links.insert(links.begin() + index + 1, sibling_pos);

			m_pgcache.put_page(sibling_pos, std::move(sibling.make_page()));
			m_pgcache.put_page(child_pos, std::move(child.make_page()));
			m_pgcache.put_page(currpos, std::move(curr.make_page()));

			if (key < midkey) {
				currpos = child_pos;
				curr = std::move(child);
			} else if (key > midkey) {
				currpos = sibling_pos;
				curr = std::move(sibling);
			}
		}
	}

	[[nodiscard]] std::optional<Val> get(const Self::Key &key) const noexcept {
		return search_subtree(root(), key);
	}

	[[nodiscard]] bool contains(const Self::Key &key) const noexcept {
		return search_subtree(root(), key).has_value();
	}

private:
	void save_header() const noexcept {
		if (m_header.dirty()) {
			m_header.rootpos() = m_rootpos;
			m_header.size() = m_size;
			m_header.dirty() = false;
		}

		nop::Serializer<nop::StreamWriter<std::ofstream>> serializer{m_header_name.data(), std::ios::trunc};
		serializer.Write(m_header) || nop::Die(std::cerr);
	}

	bool load_header() {
		nop::Deserializer<nop::StreamReader<std::ifstream>> deserializer{m_header_name.data()};
		deserializer.Read(&m_header) || nop::Die(std::cerr);
		std::cout << m_header << "\n";
		return true;
	}

	void bare_init() noexcept {
		m_rootpos = m_pgcache.get_new_pos();
		Nod root_initial{typename Nod::Metadata(typename Nod::Leaf({}, {})), m_rootpos, true};
		m_pgcache.put_page(m_rootpos, std::move(root_initial.make_page()));

		// Fill in initial header
		m_header.rootpos() = m_rootpos;
		m_header.size() = m_size;
		m_header.depth() = m_depth;
	}

public:
	/*
	 *  Persistence API
	 */

	void load() {
		auto ok = load_header();
		assert(ok);

		m_rootpos = m_header.m_rootpos;
		m_size = m_header.m_size;
		m_depth = m_header.m_depth;
	}

	void save() const {
		save_header();
		m_pgcache.flush_all();
	}

public:
	explicit Btree(std::string_view pgcache_name,
	               std::string_view btree_header_name = "/tmp/eu-btree-header",
	               bool should_load = false)
	    : m_pgcache{pgcache_name, PAGE_CACHE_SIZE},
	      m_header_name{btree_header_name} {

		assert(NUM_RECORDS_BRANCH > 1);
		assert(NUM_RECORDS_LEAF > 1);

		if (should_load)
			load();
		else
			bare_init();
	}

private:
	mutable PageCache m_pgcache;

	mutable Header m_header;
	const std::string_view m_header_name;

	Position m_rootpos;

	std::size_t m_size{0};

	std::size_t m_depth{0};
};

}// namespace internal::storage::btree


/* vector/gsl_vector_uchar.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_VECTOR_UCHAR_H__
#define __GSL_VECTOR_UCHAR_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_block_uchar.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct
{
  size_t size;
  size_t stride;
  unsigned char *data;
  gsl_block_uchar *block;
  int owner;
}
gsl_vector_uchar;

typedef struct
{
  gsl_vector_uchar vector;
} _gsl_vector_uchar_view;

typedef _gsl_vector_uchar_view gsl_vector_uchar_view;

typedef struct
{
  gsl_vector_uchar vector;
} _gsl_vector_uchar_const_view;

typedef const _gsl_vector_uchar_const_view gsl_vector_uchar_const_view;

/* Allocation */

GSL_FUN gsl_vector_uchar *gsl_vector_uchar_alloc (const size_t n);
GSL_FUN gsl_vector_uchar *gsl_vector_uchar_calloc (const size_t n);

GSL_FUN gsl_vector_uchar *gsl_vector_uchar_alloc_from_block (gsl_block_uchar * b,
                                                     const size_t offset,
                                                     const size_t n,
                                                     const size_t stride);

GSL_FUN gsl_vector_uchar *gsl_vector_uchar_alloc_from_vector (gsl_vector_uchar * v,
                                                      const size_t offset,
                                                      const size_t n,
                                                      const size_t stride);

GSL_FUN void gsl_vector_uchar_free (gsl_vector_uchar * v);

/* Views */

GSL_FUN _gsl_vector_uchar_view
gsl_vector_uchar_view_array (unsigned char *v, size_t n);

GSL_FUN _gsl_vector_uchar_view
gsl_vector_uchar_view_array_with_stride (unsigned char *base,
                                         size_t stride,
                                         size_t n);

GSL_FUN _gsl_vector_uchar_const_view
gsl_vector_uchar_const_view_array (const unsigned char *v, size_t n);

GSL_FUN _gsl_vector_uchar_const_view
gsl_vector_uchar_const_view_array_with_stride (const unsigned char *base,
                                               size_t stride,
                                               size_t n);

GSL_FUN _gsl_vector_uchar_view
gsl_vector_uchar_subvector (gsl_vector_uchar *v,
                            size_t i,
                            size_t n);

GSL_FUN _gsl_vector_uchar_view
gsl_vector_uchar_subvector_with_stride (gsl_vector_uchar *v,
                                        size_t i,
                                        size_t stride,
                                        size_t n);

GSL_FUN _gsl_vector_uchar_const_view
gsl_vector_uchar_const_subvector (const gsl_vector_uchar *v,
                                  size_t i,
                                  size_t n);

GSL_FUN _gsl_vector_uchar_const_view
gsl_vector_uchar_const_subvector_with_stride (const gsl_vector_uchar *v,
                                              size_t i,
                                              size_t stride,
                                              size_t n);

/* Operations */

GSL_FUN void gsl_vector_uchar_set_zero (gsl_vector_uchar * v);
GSL_FUN void gsl_vector_uchar_set_all (gsl_vector_uchar * v, unsigned char x);
GSL_FUN int gsl_vector_uchar_set_basis (gsl_vector_uchar * v, size_t i);

GSL_FUN int gsl_vector_uchar_fread (FILE * stream, gsl_vector_uchar * v);
GSL_FUN int gsl_vector_uchar_fwrite (FILE * stream, const gsl_vector_uchar * v);
GSL_FUN int gsl_vector_uchar_fscanf (FILE * stream, gsl_vector_uchar * v);
GSL_FUN int gsl_vector_uchar_fprintf (FILE * stream, const gsl_vector_uchar * v,
                              const char *format);

GSL_FUN int gsl_vector_uchar_memcpy (gsl_vector_uchar * dest, const gsl_vector_uchar * src);

GSL_FUN int gsl_vector_uchar_reverse (gsl_vector_uchar * v);

GSL_FUN int gsl_vector_uchar_swap (gsl_vector_uchar * v, gsl_vector_uchar * w);
GSL_FUN int gsl_vector_uchar_swap_elements (gsl_vector_uchar * v, const size_t i, const size_t j);

GSL_FUN unsigned char gsl_vector_uchar_max (const gsl_vector_uchar * v);
GSL_FUN unsigned char gsl_vector_uchar_min (const gsl_vector_uchar * v);
GSL_FUN void gsl_vector_uchar_minmax (const gsl_vector_uchar * v, unsigned char * min_out, unsigned char * max_out);

GSL_FUN size_t gsl_vector_uchar_max_index (const gsl_vector_uchar * v);
GSL_FUN size_t gsl_vector_uchar_min_index (const gsl_vector_uchar * v);
GSL_FUN void gsl_vector_uchar_minmax_index (const gsl_vector_uchar * v, size_t * imin, size_t * imax);

GSL_FUN int gsl_vector_uchar_add (gsl_vector_uchar * a, const gsl_vector_uchar * b);
GSL_FUN int gsl_vector_uchar_sub (gsl_vector_uchar * a, const gsl_vector_uchar * b);
GSL_FUN int gsl_vector_uchar_mul (gsl_vector_uchar * a, const gsl_vector_uchar * b);
GSL_FUN int gsl_vector_uchar_div (gsl_vector_uchar * a, const gsl_vector_uchar * b);
GSL_FUN int gsl_vector_uchar_scale (gsl_vector_uchar * a, const unsigned char x);
GSL_FUN int gsl_vector_uchar_add_constant (gsl_vector_uchar * a, const double x);
GSL_FUN int gsl_vector_uchar_axpby (const unsigned char alpha, const gsl_vector_uchar * x, const unsigned char beta, gsl_vector_uchar * y);
GSL_FUN unsigned char gsl_vector_uchar_sum (const gsl_vector_uchar * a);

GSL_FUN int gsl_vector_uchar_equal (const gsl_vector_uchar * u,
                            const gsl_vector_uchar * v);

GSL_FUN int gsl_vector_uchar_isnull (const gsl_vector_uchar * v);
GSL_FUN int gsl_vector_uchar_ispos (const gsl_vector_uchar * v);
GSL_FUN int gsl_vector_uchar_isneg (const gsl_vector_uchar * v);
GSL_FUN int gsl_vector_uchar_isnonneg (const gsl_vector_uchar * v);

GSL_FUN INLINE_DECL unsigned char gsl_vector_uchar_get (const gsl_vector_uchar * v, const size_t i);
GSL_FUN INLINE_DECL void gsl_vector_uchar_set (gsl_vector_uchar * v, const size_t i, unsigned char x);
GSL_FUN INLINE_DECL unsigned char * gsl_vector_uchar_ptr (gsl_vector_uchar * v, const size_t i);
GSL_FUN INLINE_DECL const unsigned char * gsl_vector_uchar_const_ptr (const gsl_vector_uchar * v, const size_t i);

#ifdef HAVE_INLINE

INLINE_FUN
unsigned char
gsl_vector_uchar_get (const gsl_vector_uchar * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return v->data[i * v->stride];
}

INLINE_FUN
void
gsl_vector_uchar_set (gsl_vector_uchar * v, const size_t i, unsigned char x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VOID ("index out of range", GSL_EINVAL);
    }
#endif
  v->data[i * v->stride] = x;
}

INLINE_FUN
unsigned char *
gsl_vector_uchar_ptr (gsl_vector_uchar * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (unsigned char *) (v->data + i * v->stride);
}

INLINE_FUN
const unsigned char *
gsl_vector_uchar_const_ptr (const gsl_vector_uchar * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (const unsigned char *) (v->data + i * v->stride);
}
#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_VECTOR_UCHAR_H__ */


//! \file heat_driver.h
//! Driver for Magnolia's heat transfer solver
#ifndef ENRICO_SURROGATE_HEAT_DRIVER_H
#define ENRICO_SURROGATE_HEAT_DRIVER_H

#include "enrico/geom.h"
#include "enrico/heat_fluids_driver.h"

#include <gsl/gsl>
#include <mpi.h>
#include <pugixml.hpp>
#include <xtensor/xtensor.hpp>

#include <cstddef>

namespace enrico {

//! Struct containing geometric information for a flow channel
struct Channel {
  //! Channel index
  int index_;

  //! Channel flow area
  double area_;

  //! Vector of rod IDs connected to this channel, all with a fractional perimeter
  //! in contact with the channel equal to 0.25
  std::vector<std::size_t> rod_ids_;
};

//! Struct containing geometry information for a cylindrical solid rod
struct Rod {
  //! Rod index
  int index_;

  //! Rod cladding outer radius
  double clad_outer_radius_;

  //! Rod cladding inner radius
  double clad_inner_radius_;

  //! Rod pellet radius
  double pellet_radius_;

  //! Vector of channel IDs connected to this rod, all with a fractional perimeter
  //! in contact with the rod equal to 0.25
  std::vector<std::size_t> channel_ids_;
};

//! Class to construct flow channels for a Cartesian lattice of pins
class ChannelFactory {
public:
  ChannelFactory(double pitch, double rod_radius)
    : pitch_(pitch)
    , radius_(rod_radius)
    , interior_area_(pitch_ * pitch_ - M_PI * radius_ * radius_)
  {}

  //! Make a corner subchannel connected to given rods
  Channel make_corner(const std::vector<std::size_t>& rods) const
  {
    Channel c;
    c.index_ = index_++;
    c.area_ = 0.25 * interior_area_;
    c.rod_ids_ = rods;
    return c;
  }

  //! Make an edge subchannel connected to given rods
  Channel make_edge(const std::vector<std::size_t>& rods) const
  {
    Channel c;
    c.index_ = index_++;
    c.area_ = 0.5 * interior_area_;
    c.rod_ids_ = rods;
    return c;
  }

  //! Make an interior subchannel connected to given rods
  Channel make_interior(const std::vector<std::size_t>& rods) const
  {
    Channel c;
    c.index_ = index_++;
    c.area_ = interior_area_;
    c.rod_ids_ = rods;
    return c;
  }

private:
  //! rod pitch
  double pitch_;

  //! rod outer radius
  double radius_;

  //! interior channel flow area, which is proportional to flow areas for all
  //! other channel types
  double interior_area_;

  //! index of constructed channel
  static int index_;
};

class RodFactory {
public:
  RodFactory(double clad_OR, double clad_IR, double pellet_OR)
    : clad_outer_r_(clad_OR)
    , clad_inner_r_(clad_IR)
    , pellet_outer_r_(pellet_OR)
  {}

  //! Make a rod connected to given channels
  Rod make_rod(const std::vector<std::size_t>& channels) const
  {
    Rod r;
    r.index_ = index_++;
    r.clad_inner_radius_ = clad_inner_r_;
    r.clad_outer_radius_ = clad_outer_r_;
    r.pellet_radius_ = pellet_outer_r_;
    r.channel_ids_ = channels;
    return r;
  }

private:
  //! Cladding outer radius
  double clad_outer_r_;

  //! Cladding inner radius
  double clad_inner_r_;

  //! Pellet outer radius
  double pellet_outer_r_;

  //! Index of constructed rod
  static int index_;
};

/**
 * Class providing surrogate thermal-hydraulic solution for a Cartesian
 * bundle of rods with upwards-flowing coolant. A conduction model is used
 * for the solid phase, with axial conduction neglected. The solid phase is
 * linked to the fluid phase by conjugate heat transfer, which is treated
 * here with a pseudo-steady-state approach where the power entering the fluid
 * matches the power in the rod at that axial elevation. It is assumed that
 * there is zero thermal resistance between the rod and the fluid.
 *
 * The fluid solution is obtained with a very simplified "subchannel" method
 * that neglects all crossflow terms between channels such that the method
 * is more akin to a single-pin analysis in a coolant-centered basis. The
 * enthalpy is solved by simply axial energy balance, while the axial momentum
 * equation is solved for pressure (the mass flow rate in each channel being
 * fixed) while neglecting friction effects.
 */
class SurrogateHeatDriver : public HeatFluidsDriver {
public:
  //! Initializes heat-fluids surrogate with the given MPI communicator.
  //!
  //! \param comm  The MPI communicator used to initialze the surrogate
  //! \param node  XML node containing settings for surrogate
  explicit SurrogateHeatDriver(MPI_Comm comm, pugi::xml_node node);

  //! Verbosity options for printing simulation results
  enum class verbose { NONE, LOW, HIGH };

  bool has_coupling_data() const final { return comm_.rank == 0; }

  //! Get the number of local mesh elements
  //! \return Number of local mesh elements
  int n_local_elem() const override;

  //! Get the number of global mesh elements
  //! \return Number of global mesh elements
  std::size_t n_global_elem() const override;

  //! Set the heat source for a given local element
  //!
  //! \param local_elem A local element ID
  //! \param heat A heat source term
  //! \return Error code
  int set_heat_source_at(int32_t local_elem, double heat) override;

  //! Solves the heat-fluids surrogate solver
  void solve_step() final;

  void solve_heat();

  void solve_fluid();

  //! Returns Number of rings in fuel and clad
  std::size_t n_rings() const { return n_fuel_rings_ + n_clad_rings_; }

  //! Returns cladding inner radius
  double clad_inner_radius() const { return clad_inner_radius_; }

  //! Returns cladding outer radius
  double clad_outer_radius() const { return clad_outer_radius_; }

  //! Returns pellet outer radius
  double pellet_radius() const { return pellet_radius_; }

  //! Returns number of fuel rings
  std::size_t n_fuel_rings() const { return n_fuel_rings_; }

  //! Returns number of clad rings
  std::size_t n_clad_rings() const { return n_clad_rings_; }

  //! Returns number of pins in x-direction
  std::size_t n_pins_x() const { return n_pins_x_; }

  //! Returns number of pins in y-direction
  std::size_t n_pins_y() const { return n_pins_y_; }

  //! Returns pin pitch
  double pin_pitch() const { return pin_pitch_; }

  //! Returns inlet temperature boundary condition in [K]
  double inlet_temperature() const { return inlet_temperature_; }

  //! Returns inlet mass flowrate boundary condition in [kg/s]
  double mass_flowrate() const { return mass_flowrate_; }

  //! Returns maximum number of subchannel iterations
  std::size_t max_subchannel_its() const { return max_subchannel_its_; }

  //! Returns subchannel convergence tolerance for enthalpy
  double subchannel_tol_h() const { return subchannel_tol_h_; }

  //! Returns subchannel convergence tolerance for pressure
  double subchannel_tol_p() const { return subchannel_tol_p_; }

  //! Returns convergence tolerance for solid energy equation
  double heat_tol() const { return heat_tol_; }

  //! Write data to VTK
  void write_step(int timestep, int iteration) final;

  //! Returns solid temperature in [K] for given region
  double solid_temperature(std::size_t pin, std::size_t axial, std::size_t ring) const;

  //! Returns fluid density in [g/cm^3] for given region
  double fluid_density(std::size_t pin, std::size_t axial) const;

  //! Returns fluid temperature in [K] for given region
  double fluid_temperature(std::size_t pin, std::size_t axial) const;

  // Data on fuel pins
  xt::xtensor<double, 2> pin_centers_; //!< (x,y) values for center of fuel pins
  xt::xtensor<double, 1> z_;           //!< Bounding z-values for axial segments
  std::size_t n_axial_;                //!< number of axial segments
  std::size_t n_azimuthal_{4};         //!< number of azimuthal segments

  //! Total number of pins
  std::size_t n_pins_;

  // Dimensions for a single fuel pin axial segment
  double clad_outer_radius_;     //!< clad outer radius in [cm]
  double clad_inner_radius_;     //!< clad inner radius in [cm]
  double pellet_radius_;         //!< fuel pellet radius in [cm]
  std::size_t n_fuel_rings_{20}; //!< number of fuel rings
  std::size_t n_clad_rings_{2};  //!< number of clad rings

  //!< Channels in the domain
  std::vector<Channel> channels_;

  //!< Rods in the domain
  std::vector<Rod> rods_;

  //! Mass flowrate for coolant-centered channels; this is determine by distributing
  //! a total inlet mass flowrate among the channels based on the fractional flow area.
  xt::xtensor<double, 1> channel_flowrates_;

  // solver variables and settings
  xt::xtensor<double, 4>
    source_; //!< heat source for each (pin, axial segment, ring, azimuthal segment)
  xt::xtensor<double, 1> r_grid_clad_; //!< radii of each clad ring in [cm]
  xt::xtensor<double, 1> r_grid_fuel_; //!< radii of each fuel ring in [cm]

  //! Cross-sectional areas of rings in fuel and cladding
  xt::xtensor<double, 1> solid_areas_;

  // visualization
  std::string viz_basename_{
    "heat_surrogate"}; //!< base filename for visualization files (default: magnolia)
  std::string viz_iterations_{
    "none"};                    //!< visualization iterations to write (none, all, final)
  std::string viz_data_{"all"}; //!< visualization data to write
  std::string viz_regions_{"all"}; //!< visualization regions to write
  size_t vtk_radial_res_{20};      //!< radial resolution of resulting vtk files

private:
  //! Get temperature of local mesh elements
  //! \return Temperature of local mesh elements in [K]
  std::vector<double> temperature_local() const override;

  //! Get density of local mesh elements
  //! \return Density of local mesh elements in [g/cm^3]
  std::vector<double> density_local() const override;

  //! States whether each local region is in fluid
  //! \return For each local region, 1 if region is in fluid and 0 otherwise
  std::vector<int> fluid_mask_local() const override;

  //! Get centroids of local mesh elements
  //! \return Centroids of local mesh elements
  std::vector<Position> centroid_local() const override;

  //! Get volumes of local mesh elements
  //! \return Volumes of local mesh elements
  std::vector<double> volume_local() const override;

  //! Create internal arrays used for heat equation solver
  void generate_arrays();

  //! Channel index in terms of row, column index
  int channel_index(int row, int col) const { return row * (n_pins_x_ + 1) + col; }

  //! Rod power at a given node in a given pin, computed by integrating the heat source
  //! (assumed constant in each ring) over the pin.
  //! \param pin   pin index
  //! \param axial axial index
  double rod_axial_node_power(const int pin, const int axial) const;

  //! Diagnostic function to assess whether the mass is conserved by the subchannel
  //! solver by comparing the mass flowrate in each axial plane (at cell-centered
  //! positions) to the specified inlet mass flowrate.
  //! \param rho density in a cell-centered basis
  //! \param u   axial velocity in a face-centered basis
  bool is_mass_conserved(const xt::xtensor<double, 2>& rho,
                         const xt::xtensor<double, 2>& u) const;

  //! Diagnostic function to assess whether the energy is conserved by the subchannel
  //! solver by comparing the energy deposition in each channel in each axial plane
  //! (at cell-centered positions) to the powers of the rods connected to that channel.
  //! \param rho density in a cell-centered basis
  //! \param u   axial velocity in a face-centered basis
  //! \param h   enthalpy in a face-centered basis
  //! \param q   powers in each channel in a cell-centered basis
  bool is_energy_conserved(const xt::xtensor<double, 2>& rho,
                           const xt::xtensor<double, 2>& u,
                           const xt::xtensor<double, 2>& h,
                           const xt::xtensor<double, 2>& q) const;

  //!< solid temperature in [K] for each (pin, axial segment, ring)
  xt::xtensor<double, 3> solid_temperature_;

  //! Flow areas for coolant-centered channels
  xt::xtensor<double, 1> channel_areas_;

  //! Fluid temperature in a rod-centered basis indexed by rod ID and axial ID
  xt::xtensor<double, 2> fluid_temperature_;

  //! Fluid density in [g/cm^3] in a rod-centered basis indexed by rod ID and axial ID
  xt::xtensor<double, 2> fluid_density_;

  //! Number of pins in the x-direction in a Cartesian grid
  std::size_t n_pins_x_;

  //! Number of pins in the y-direction in a Cartesian grid
  std::size_t n_pins_y_;

  //! Pin pitch, assumed the same for the x and y directions
  double pin_pitch_;

  //! Inlet fluid temperature [K]
  double inlet_temperature_;

  //! Mass flowrate of fluid into the domain [kg/s]
  double mass_flowrate_;

  //! Number of channels
  std::size_t n_channels_;

  //! Maximum number of iterations for subchannel solution, set to a default value
  //! of 100 if not set by the user
  int max_subchannel_its_ = 100;

  //! Convergence tolerance on enthalpy for the subchannel solution for use in
  //! convergence based on the L-1 norm, set to a default value of 1e-2
  double subchannel_tol_h_ = 1e-2;

  //! Convergence tolerance on pressure for the subchannel solution for use in
  //! convergence based on the L-1 norm, set to a default value of 1e-2
  double subchannel_tol_p_ = 1e-2;

  //! Convergence tolerance for solid temperature solution, set to a default value
  //! of 1e-4
  double heat_tol_ = 1e-4;

  //! Gravitational acceleration
  const double g_ = 9.81;

  //! Verbosity setting for printing simulation results; defaults to NONE
  verbose verbosity_ = verbose::NONE;

}; // end SurrogateHeatDriver

} // namespace enrico

#endif // ENRICO_SURROGATE_HEAT_DRIVER_H


#ifndef AMICI_MISC_H
#define AMICI_MISC_H

#include "amici/defines.h"
#include <sunmatrix/sunmatrix_sparse.h> // SUNMatrixContent_Sparse

#include <algorithm>
#include <vector>
#include <memory>
#include <regex>

#include <gsl/gsl-lite.hpp>

namespace amici {

/**
 * @brief creates a slice from existing data
 *
 * @param data to be sliced
 * @param index slice index
 * @param size slice size
 * @return span of the slice
 */

 gsl::span<realtype> slice(std::vector<realtype> &data, int index,
                           unsigned size);

/**
  * @brief Remove parameter scaling according to the parameter scaling in pscale
  *
  * All vectors must be of same length.
  *
  * @param bufferScaled scaled parameters
  * @param pscale parameter scaling
  * @param bufferUnscaled unscaled parameters are written to the array
  */
void unscaleParameters(gsl::span<const realtype> bufferScaled,
                       gsl::span<const ParameterScaling> pscale,
                       gsl::span<realtype> bufferUnscaled);

/**
  * @brief Remove parameter scaling according to `scaling`
  *
  * @param scaledParameter scaled parameter
  * @param scaling parameter scaling
  *
  * @return Unscaled parameter
  */
double getUnscaledParameter(double scaledParameter, ParameterScaling scaling);

/**
 * @brief Apply parameter scaling according to `scaling`
 * @param unscaledParameter
 * @param scaling parameter scaling
 * @return Scaled parameter
 */
double getScaledParameter(double unscaledParameter, ParameterScaling scaling);

/**
 * @brief Apply parameter scaling according to `scaling`
 * @param bufferUnscaled
 * @param pscale parameter scaling
 * @param bufferScaled destination
 */
void scaleParameters(gsl::span<const realtype> bufferUnscaled,
                     gsl::span<const ParameterScaling> pscale,
                     gsl::span<realtype> bufferScaled);

/**
 * @brief Returns the current backtrace as std::string
 * @param maxFrames Number of frames to include
 * @return Backtrace
 */
std::string backtraceString(int maxFrames);

/**
 * @brief Convert std::regex_constants::error_type to string
 * @param err_type error type
 * @return Error type as string
 */
std::string regexErrorToString(std::regex_constants::error_type err_type);

/**
 * @brief Format printf-style arguments to std::string
 * @param fmt Format string
 * @param ap Argument list pointer
 * @return Formatted String
 */
std::string printfToString(const char *fmt, va_list ap);

} // namespace amici

#ifndef __cpp_lib_make_unique
// custom make_unique while we are still using c++11
namespace std {
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
#endif

#endif // AMICI_MISC_H


/**
 *
 * @file core_blas.h
 *
 *  PLASMA auxiliary routines
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.6.0
 * @author Jakub Kurzak
 * @author Hatem Ltaief
 * @date 2010-11-15
 *
 **/
#ifndef _PLASMA_CORE_BLAS_H_
#define _PLASMA_CORE_BLAS_H_

#include <cblas.h>
#include "plasmatypes.h"
#include "descriptor.h"

#include "core_zblas.h"
#include "core_dblas.h"
#include "core_cblas.h"
#include "core_sblas.h"
#include "core_zcblas.h"
#include "core_dsblas.h"

#ifdef __cplusplus
extern "C" {
#endif

  /*
   * Coreblas Error
   */
#define coreblas_error(k, str) fprintf(stderr, "%s: Parameter %d / %s\n", __func__, k, str);

 /** ****************************************************************************
  *  LAPACK Constants
  **/
extern char *plasma_lapack_constants[];
#define lapack_const(plasma_const) plasma_lapack_constants[plasma_const][0]

  /*
   * CBlas enum
   */
#define CBLAS_TRANSPOSE enum CBLAS_TRANSPOSE
#define CBLAS_UPLO      enum CBLAS_UPLO
#define CBLAS_DIAG      enum CBLAS_DIAG
#define CBLAS_SIDE      enum CBLAS_SIDE

/* CBLAS requires for scalar arguments to be passed by address rather than by value */
#ifndef CBLAS_SADDR
#define CBLAS_SADDR( _val_ ) &(_val_)
#endif

 /** ****************************************************************************
  *  External interface of the GKK algorithm for InPlace Layout Translation
  **/
int  GKK_minloc(int n, int *T);
void GKK_BalanceLoad(int thrdnbr, int *Tp, int *leaders, int nleaders, int L);
int  GKK_getLeaderNbr(int me, int ne, int *nleaders, int **leaders);

/** ****************************************************************************
 *  Extra quark wrapper functions that do not rely on precision
 *  (Defined only if quark.h is included prior to this file)
 **/
#if defined(QUARK_H)
  /*
   * Functions which don't depend on precision
   */
void CORE_free_quark(Quark *quark);
void CORE_foo_quark(Quark *quark);
void CORE_foo2_quark(Quark *quark);

void QUARK_CORE_free(Quark *quark, Quark_Task_Flags *task_flags,
                     void *A, int szeA);

void CORE_pivot_update(int m, int n, int *ipiv, int *indices,
                       int offset, int init);
void CORE_pivot_update_quark(Quark *quark);
void QUARK_CORE_pivot_update(Quark *quark, Quark_Task_Flags *task_flags,
                             int m, int n, int *ipiv, int *indices,
                             int offset, int init);
#endif /* defined(QUARK_H) */

#ifdef __cplusplus
}
#endif

#endif /* _PLASMA_CORE_BLAS_H_ */


#ifndef libceed_solids_examples_misc_h
#define libceed_solids_examples_misc_h

#include <ceed.h>
#include <petsc.h>
#include "../include/structs.h"

// -----------------------------------------------------------------------------
// Context setup
// -----------------------------------------------------------------------------
// Setup context data for Jacobian evaluation
PetscErrorCode SetupJacobianCtx(MPI_Comm comm, AppCtx app_ctx, DM dm, Vec V,
                                Vec V_loc, CeedData ceed_data, Ceed ceed,
                                CeedQFunctionContext ctx_phys,
                                CeedQFunctionContext ctx_phys_smoother,
                                UserMult jacobian_ctx);

// Setup context data for prolongation and restriction operators
PetscErrorCode SetupProlongRestrictCtx(MPI_Comm comm, AppCtx app_ctx, DM dm_c,
                                       DM dm_f, Vec V_f, Vec V_loc_c, Vec V_loc_f,
                                       CeedData ceed_data_c, CeedData ceed_data_f,
                                       Ceed ceed,
                                       UserMultProlongRestr prolong_restr_ctx);

// -----------------------------------------------------------------------------
// Jacobian setup
// -----------------------------------------------------------------------------
PetscErrorCode FormJacobian(SNES snes, Vec U, Mat J, Mat J_pre, void *ctx);

// -----------------------------------------------------------------------------
// Solution output
// -----------------------------------------------------------------------------
PetscErrorCode ViewSolution(MPI_Comm comm, AppCtx app_ctx, Vec U,
                            PetscInt increment, PetscScalar load_increment);

PetscErrorCode ViewDiagnosticQuantities(MPI_Comm comm, DM dm_U,
                                        UserMult user, AppCtx app_ctx, Vec U,
                                        CeedElemRestriction elem_restr_diagnostic);

// -----------------------------------------------------------------------------
// Regression testing
// -----------------------------------------------------------------------------
PetscErrorCode RegressionTests_solids(AppCtx app_ctx, PetscReal energy);

#endif // libceed_solids_examples_misc_h