/*
Copyright 2010-2011, D. E. Shaw Research.
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 D. E. Shaw Research 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.
*/
#ifndef __r123_compat_gslrng_dot_h__
#define __r123_compat_gslrng_dot_h__

#include <gsl/gsl_rng.h>
#include <string.h>

/**
   The macro:  GSL_CBRNG(NAME, CBRNGNAME)
   declares the necessary structs and  constants that define a
   gsl_rng_NAME type based on the counter-based RNG CBRNGNAME.  For example:

   Usage:

   @code
   #include <Random123/threefry.h>
   #include <Random123/conventional/gsl_cbrng.h>  // this file
   GSL_CBRNG(cbrng, threefry4x32); // creates gsl_rng_cbrng

   int main(int argc, char **argv){
       gsl_rng *r = gsl_rng_alloc(gsl_rng_cbrng);
       ... use r as you would use any other gsl_rng ...
    }
    @endcode

    It requires that NAME be the name of a CBRNG that follows the
    naming and stylistic conventions of the Random123 library.

    Note that wrapping a \ref CBRNG "counter-based PRNG" with a traditional API in
    this way obscures much of the power of the CBRNG API.
    Nevertheless, it may be of value to applications that are already
    coded to work with GSL random number generators, and that wish
    to use the RNGs in the Random123 library.

 */

#define GSL_CBRNG(NAME, CBRNGNAME)                                      \
const gsl_rng_type *gsl_rng_##NAME;                                     \
                                                                        \
typedef struct{                                                         \
    CBRNGNAME##_ctr_t ctr;                                                   \
    CBRNGNAME##_ctr_t r;                                                     \
    CBRNGNAME##_key_t key;                                                   \
    int elem;                                                           \
} NAME##_state;                                                         \
                                                                        \
static unsigned long int NAME##_get(void *vstate){                      \
    NAME##_state *st = (NAME##_state *)vstate;                          \
    const int N=sizeof(st->ctr.v)/sizeof(st->ctr.v[0]);                 \
    if( st->elem == 0 ){                                                \
        ++st->ctr.v[0];                                                 \
        if( N>1 && st->ctr.v[0] == 0 ) ++st->ctr.v[1];                  \
        if( N>2 && st->ctr.v[1] == 0 ) ++st->ctr.v[2];                  \
        if( N>3 && st->ctr.v[2] == 0 ) ++st->ctr.v[3];                  \
        st->r = CBRNGNAME(st->ctr, st->key);                                 \
        st->elem = N;                                                   \
    }                                                                   \
    return st->r.v[--st->elem];                                         \
}                                                                       \
                                                                        \
static double NAME##_get_double (void * vstate);                        \
                                                                        \
static void NAME##_set(void *vstate, unsigned long int s){              \
    NAME##_state *st = (NAME##_state *)vstate;                          \
    st->elem = 0;                                                       \
    /* Assume that key and ctr have an array member, v,                 \
       as if they are r123arrayNxW.  If not, this will fail             \
       to compile.  In particular, this macro fails to compile          \
       when the underlying CBRNG requires use of keyinit */             \
    memset(&st->ctr.v[0], 0, sizeof(st->ctr.v));                        \
    memset(&st->key.v[0], 0, sizeof(st->key.v));                        \
    /* GSL 1.15 documentation says this about gsl_rng_set:              \
         Note that the most generators only accept 32-bit seeds, with higher \
         values being reduced modulo 2^32.  For generators with smaller \
         ranges the maximum seed value will typically be lower.         \
     so we won't jump through any hoops here to deal with               \
     high bits if sizeof(unsigned long) > sizeof(uint32_t). */          \
    st->key.v[0] = s;                                                   \
}                                                                       \
                                                                        \
static const gsl_rng_type NAME##_type = {                               \
    #NAME,                                                              \
    ~0UL>>((R123_W(CBRNGNAME##_ctr_t)>=8*sizeof(unsigned long))? 0 : (8*sizeof(unsigned long) - R123_W(CBRNGNAME##_ctr_t))),     \
    0,                                                                  \
    sizeof(NAME##_state),                                               \
    &NAME##_set,                                                        \
    &NAME##_get,                                                        \
    &NAME##_get_double                                                  \
};                                                                      \
                                                                        \
static double                                                           \
NAME##_get_double (void * vstate)                                       \
{                                                                       \
    return NAME##_get (vstate)/(double)NAME##_type.max;                 \
}                                                                       \
                                                                        \
const gsl_rng_type *gsl_rng_##NAME = &NAME##_type

#endif


/*	$Id$ */
/*
 * Copyright (c) 2014, 2015 Kristaps Dzonsons <kristaps@kcons.eu>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#ifdef MAC_INTEGRATION
#include <gtkosxapplication.h>
#endif
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_multifit.h>
#include <gsl/gsl_histogram.h>
#include <kplot.h>

#include "extern.h"

/*
 * Brute-force scan all possible pi values (and Poisson means) by
 * scanning through the strategy space.
 */
int
rangefind(struct bmigrate *b)
{
	size_t		 mutants;
	double		 mstrat, istrat, v;
	gchar		 buf[22];

	g_assert(b->rangeid);

	/*
	 * Set the number of mutants on a given island, then see what
	 * the utility function would yield given that number of mutants
	 * and incumbents, setting the current player to be one or the
	 * other..
	 */
	mstrat = istrat = 0.0;
	for (mutants = 0; mutants <= b->range.n; mutants++) {
		mstrat = b->range.ymin +
			(b->range.slicey / (double)b->range.slices) *
			(b->range.ymax - b->range.ymin);
		istrat = b->range.xmin +
			(b->range.slicex / (double)b->range.slices) *
			(b->range.xmax - b->range.xmin);
		/*
		 * Only check for a given mutant/incumbent individual's
		 * strategy if the population is going to support the
		 * existence of that individual.
		 */
		if (mutants > 0) {
			v = hnode_exec
				((const struct hnode *const *)
				 b->range.exp,
				 istrat, mstrat * mutants + istrat *
				 (b->range.n - mutants), b->range.n);
			if (0.0 != v && ! isnormal(v))
				break;
			if (v < b->range.pimin)
				b->range.pimin = v;
			if (v > b->range.pimax)
				b->range.pimax = v;
			b->range.piaggr += v;
			b->range.picount++;
		}
		if (mutants != b->range.n) {
			v = hnode_exec
				((const struct hnode *const *)
				 b->range.exp,
				 mstrat, mstrat * mutants + istrat *
				 (b->range.n - mutants), b->range.n);
			if (0.0 != v && ! isnormal(v))
				break;
			if (v < b->range.pimin)
				b->range.pimin = v;
			if (v > b->range.pimax)
				b->range.pimax = v;
			b->range.piaggr += v;
			b->range.picount++;
		}
	}

	/*
	 * We might have hit a discontinuous number.
	 * If we did, then print out an error and don't continue.
	 * If not, update to the next mutant and incumbent.
	 */
	if (mutants <= b->range.n) {
		g_snprintf(buf, sizeof(buf),
			"%zu mutants, mutant=%g, incumbent=%g",
			mutants, mstrat, istrat);
		gtk_label_set_text(b->wins.rangeerror, buf);
		gtk_widget_show_all(GTK_WIDGET(b->wins.rangeerrorbox));
		g_debug("Range-finder idle event complete (error)");
		b->rangeid = 0;
	} else {
		if (++b->range.slicey == b->range.slices) {
			b->range.slicey = 0;
			b->range.slicex++;
		}
		if (b->range.slicex == b->range.slices) {
			g_debug("Range-finder idle event complete");
			b->rangeid = 0;
		}
	}

	/*
	 * Set our current extrema.
	 */
	g_snprintf(buf, sizeof(buf), "%g", b->range.pimin);
	gtk_label_set_text(b->wins.rangemin, buf);
	g_snprintf(buf, sizeof(buf), "%g", b->range.alpha *
		(1.0 + b->range.delta * b->range.pimin));
	gtk_label_set_text(b->wins.rangeminlambda, buf);

	g_snprintf(buf, sizeof(buf), "%g", b->range.pimax);
	gtk_label_set_text(b->wins.rangemax, buf);
	g_snprintf(buf, sizeof(buf), "%g", b->range.alpha *
		(1.0 + b->range.delta * b->range.pimax));
	gtk_label_set_text(b->wins.rangemaxlambda, buf);

	v = b->range.piaggr / (double)b->range.picount;
	g_snprintf(buf, sizeof(buf), "%g", v);
	gtk_label_set_text(b->wins.rangemean, buf);
	g_snprintf(buf, sizeof(buf), "%g", b->range.alpha *
		(1.0 + b->range.delta * v));
	gtk_label_set_text(b->wins.rangemeanlambda, buf);

	v = (b->range.slicex * b->range.slices + b->range.slicey) /
		(double)(b->range.slices * b->range.slices);
	g_snprintf(buf, sizeof(buf), "%.1f%%", v * 100.0);
	gtk_label_set_text(b->wins.rangestatus, buf);

	return(0 != b->rangeid);
}


// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#pragma once

#include <algorithm>
#include <boost/iostreams/categories.hpp>
#include <gsl/gsl>
#include <iosfwd>
#include <vector>

namespace mira
{
    class memory_device
    {
    public:
        using char_type = char;
        using category = boost::iostreams::seekable_device_tag;

        memory_device(std::vector<char>& memory, std::streamoff pos)
            : m_pos{ pos }
            , m_memory{ memory }
        {}

        std::streamoff position() const
        {
            return m_pos;
        }

        void reset()
        {
            m_pos = 0;
        }

        std::streamsize read(char* s, std::streamsize n)
        {
            // Read up to n characters from the underlying data source
            // into the buffer s, returning the number of characters
            // read; return -1 to indicate EOF
            std::streamsize read = std::min<std::streamsize>(m_memory.size() - m_pos, n);
            if (read == 0)
                return -1;

            std::copy(pointer(), pointer() + gsl::narrow_cast<ptrdiff_t>(read), s);
            m_pos += read;

            return read;
        }

        std::streamsize write(const char* s, std::streamsize n)
        {
            // Write up to n characters to the underlying
            // data sink into the buffer s, returning the
            // number of characters written
            std::streamsize written = 0ll;
            if (m_pos != gsl::narrow<std::streamoff>(m_memory.size()))
            {
                written = std::min<std::streamsize>(n, m_memory.size() - m_pos);
                std::copy(s,
                          s + gsl::narrow_cast<ptrdiff_t>(written),
                          m_memory.begin() + gsl::narrow_cast<ptrdiff_t>(m_pos));
                m_pos += written;
            }

            if (written < n)
            {
                m_memory.insert(m_memory.end(), s + written, s + n);
                m_pos = gsl::narrow<std::streamoff>(m_memory.size());
            }

            return n;
        }

        std::streamoff seek(std::streamoff off, std::ios_base::seekdir way)
        {
            // Seek to position off and return the new stream
            // position. The argument way indicates how off is
            // interpretted:
            //    - std::ios_base::beg indicates an offset from the
            //      sequence beginning
            //    - std::ios_base::cur indicates an offset from the
            //      current character position
            //    - std::ios_base::end indicates an offset from the
            //      sequence end

            std::streamoff next;
            if (way == std::ios_base::beg)
            {
                next = off;
            }
            else if (way == std::ios_base::cur)
            {
                next = m_pos + off;
            }
            else if (way == std::ios_base::end)
            {
                next = m_memory.size() + off - 1;
            }
            else
            {
                throw std::ios_base::failure("bad seek direction");
            }

            // Check for errors
            if (next < 0 || next > gsl::narrow<std::streamoff>(m_memory.size()))
            {
                throw std::ios_base::failure("bad seek offset");
            }

            m_pos = next;
            return m_pos;
        }

    private:
        char* pointer()
        {
            return &m_memory[gsl::narrow_cast<ptrdiff_t>(m_pos)];
        }

        std::streamoff m_pos{0};
        std::vector<char>& m_memory;
    };
}


#pragma once

#include "file_descriptor.h"
#include <filesystem>
#include <gsl/span>
#include <random>

namespace dogbox
{
    inline void create_randomness(gsl::span<std::byte> const into)
    {
        file_descriptor const random = open_file_for_reading("/dev/urandom").value();
        ptrdiff_t written = 0;
        while (written < into.size())
        {
            size_t const reading = static_cast<size_t>(into.size() - written);
            ssize_t const read_result = read(random.handle, into.data() + written, reading);
            if (read_result < 0)
            {
                TO_DO();
            }
            written += reading;
        }
    }
}


#pragma once

#include "PropertyType.h"

#include <CesiumUtility/SpanHelper.h>

#include <gsl/span>

#include <cassert>
#include <cstddef>

namespace CesiumGltf {
template <typename ElementType> class MetadataArrayView {
public:
  MetadataArrayView() : _valueBuffer{} {}

  MetadataArrayView(const gsl::span<const std::byte>& buffer) noexcept
      : _valueBuffer{
            CesiumUtility::reintepretCastSpan<const ElementType>(buffer)} {}

  const ElementType& operator[](int64_t index) const noexcept {
    return _valueBuffer[index];
  }

  int64_t size() const noexcept {
    return static_cast<int64_t>(_valueBuffer.size());
  }

private:
  gsl::span<const ElementType> _valueBuffer;
};

template <> class MetadataArrayView<bool> {
public:
  MetadataArrayView() : _valueBuffer{}, _bitOffset{0}, _instanceCount{0} {}

  MetadataArrayView(
      const gsl::span<const std::byte>& buffer,
      int64_t bitOffset,
      int64_t instanceCount) noexcept
      : _valueBuffer{buffer},
        _bitOffset{bitOffset},
        _instanceCount{instanceCount} {}

  bool operator[](int64_t index) const noexcept {
    index += _bitOffset;
    const int64_t byteIndex = index / 8;
    const int64_t bitIndex = index % 8;
    const int bitValue =
        static_cast<int>(_valueBuffer[byteIndex] >> bitIndex) & 1;
    return bitValue == 1;
  }

  int64_t size() const noexcept { return _instanceCount; }

private:
  gsl::span<const std::byte> _valueBuffer;
  int64_t _bitOffset;
  int64_t _instanceCount;
};

template <> class MetadataArrayView<std::string_view> {
public:
  MetadataArrayView()
      : _valueBuffer{}, _offsetBuffer{}, _offsetType{}, _size{0} {}

  MetadataArrayView(
      const gsl::span<const std::byte>& buffer,
      const gsl::span<const std::byte>& offsetBuffer,
      PropertyType offsetType,
      int64_t size) noexcept
      : _valueBuffer{buffer},
        _offsetBuffer{offsetBuffer},
        _offsetType{offsetType},
        _size{size} {}

  std::string_view operator[](int64_t index) const noexcept {
    const size_t currentOffset =
        getOffsetFromOffsetBuffer(index, _offsetBuffer, _offsetType);
    const size_t nextOffset =
        getOffsetFromOffsetBuffer(index + 1, _offsetBuffer, _offsetType);
    return std::string_view(
        reinterpret_cast<const char*>(_valueBuffer.data() + currentOffset),
        (nextOffset - currentOffset));
  }

  int64_t size() const noexcept { return _size; }

private:
  static size_t getOffsetFromOffsetBuffer(
      size_t instance,
      const gsl::span<const std::byte>& offsetBuffer,
      PropertyType offsetType) noexcept {
    switch (offsetType) {
    case PropertyType::Uint8: {
      assert(instance < offsetBuffer.size() / sizeof(uint8_t));
      const uint8_t offset = *reinterpret_cast<const uint8_t*>(
          offsetBuffer.data() + instance * sizeof(uint8_t));
      return static_cast<size_t>(offset);
    }
    case PropertyType::Uint16: {
      assert(instance < offsetBuffer.size() / sizeof(uint16_t));
      const uint16_t offset = *reinterpret_cast<const uint16_t*>(
          offsetBuffer.data() + instance * sizeof(uint16_t));
      return static_cast<size_t>(offset);
    }
    case PropertyType::Uint32: {
      assert(instance < offsetBuffer.size() / sizeof(uint32_t));
      const uint32_t offset = *reinterpret_cast<const uint32_t*>(
          offsetBuffer.data() + instance * sizeof(uint32_t));
      return static_cast<size_t>(offset);
    }
    case PropertyType::Uint64: {
      assert(instance < offsetBuffer.size() / sizeof(uint64_t));
      const uint64_t offset = *reinterpret_cast<const uint64_t*>(
          offsetBuffer.data() + instance * sizeof(uint64_t));
      return static_cast<size_t>(offset);
    }
    default:
      assert(false && "Offset type has unknown type");
      return 0;
    }
  }
  gsl::span<const std::byte> _valueBuffer;
  gsl::span<const std::byte> _offsetBuffer;
  PropertyType _offsetType;
  int64_t _size;
};
} // namespace CesiumGltf


#pragma once

#include <type_traits>

#include <cuda/define_specifiers.hpp>
#include <cuda/runtime_api.hpp>

#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/zip_iterator.h>

#include <gsl-lite/gsl-lite.hpp>

#include <cub/cub.cuh>

#include <thrustshift/constant.h>
#include <thrustshift/math.h>
#include <thrustshift/not-a-vector.h>

namespace thrustshift {

namespace device_function {

namespace implicit_unroll {

/*! \brief Write the selected values to the result if select_op is true.
 *
 *  All threads check if their value should be selected. Afterwards, it is
 *  determined within the warp how many values were selected. Then, the first
 *  in the warp determines the range in the result, which is reserved for the
 *  warp via an atomic increment on `result_pos`. Subsequently, each thread with
 *  a selected value and `valid_write` writes the result into the reserved range.
 *  Only full warps are allowed to enter this function.
 *
 *  \param x the value for each thread
 *  \param selected_values result range.
 *  \param selected_values_pos to an integer holding the ID of the first
 *      written result element by this function (usually initialized with
 *      zero). This counter is read and written atomically by the first lane of
 *      the warp. Usually this counter is shared among threads because it is
 *      incremented and read atomically.
 *  \param lane_id ID of the thread within the warp.
 *  \param valid_write some threads might be disabled with this flag (useful for
 *      handling range borders).
 *  \param select_op lambda to select the values.
 */
template <typename T, typename It, typename Bool, class F>
CUDA_FD void select_if_warp_aggregated(T x,
                                       It selected_values,
                                       int* selected_values_pos,
                                       int lane_id,
                                       Bool valid_write,
                                       F select_op) {

	const bool p = select_op(x) && valid_write;

	const unsigned umask = __ballot_sync(0xffffffff, p);
	const int num_selected_values = __popc(umask);

	constexpr int source_lane = 0;
	int pos;
	if (lane_id == source_lane) {
		pos = atomicAdd(selected_values_pos, num_selected_values);
	}
	const unsigned umask_before_me =
	    (~unsigned(0)) >> (sizeof(unsigned) * 8 - lane_id);
	const int num_selected_values_before_me = __popc(umask & umask_before_me);
	pos = __shfl_sync(0xffffffff, pos, source_lane);
	pos += num_selected_values_before_me;
	if (p) {
		selected_values[pos] = x;
	}
}

/*! \brief select_if as a block level primitive.
 *
 *  \param values iterator to range of length N
 *  \param N length of input values
 *  \param selected_values iterator to range of length `*selected_values_pos + N`
 *  \param selected_values_pos pointer to an integer holding the ID of the first
 *      written selected_values element by this function (usually initialized
 *      with zero). This counter must be shared among all threads, which
 *      enter this function because it is incremented and read atomically.
 *  \param tid thread ID
 *  \param num_threads number of threads which enter this function.
 *  \param select_op lambda to select the values.
 */
template <typename It, typename ItResult, typename I0, typename I1, class F>
CUDA_FD void select_if(It values,
                       I0 N,
                       ItResult selected_values,
                       int* selected_values_pos,
                       int tid,
                       I1 num_threads,
                       F select_op) {

	const int num_tiles = thrustshift::ceil_divide(N, num_threads);
	for (int tile_id = 0; tile_id < num_tiles - 1; ++tile_id) {
		const int j = tile_id * num_threads + tid;
		auto x = values[j];
		select_if_warp_aggregated(x,
		                          selected_values,
		                          selected_values_pos,
		                          tid % warp_size,
		                          std::bool_constant<true>(),
		                          select_op);
	}
	auto rest = N % num_threads;
	if (rest > 0) {
		const int j = (num_tiles - 1) * num_threads + tid;
		const bool valid_rw = tid < rest;
		using T = typename std::remove_const<
		    typename std::iterator_traits<It>::value_type>::type;
		const auto x = [&]() -> T {
			if (valid_rw) {
				return values[j];
			}
			return T{};
		}();
		select_if_warp_aggregated(x,
		                          selected_values,
		                          selected_values_pos,
		                          tid % warp_size,
		                          valid_rw,
		                          select_op);
	}
}

} // namespace implicit_unroll

} // namespace device_function

namespace async {

template <class ValuesRange,
          class SelectedRange,
          class NumSelectedPtr,
          class SelectOp,
          class MemoryResource>
void select_if(cuda::stream_t& stream,
               ValuesRange&& values,
               SelectedRange&& selected,
               NumSelectedPtr num_selected_ptr,
               SelectOp select_op,
               MemoryResource& delayed_memory_resource) {

	const std::size_t N = values.size();

	gsl_Expects(selected.size() == N);

	size_t tmp_bytes_size = 0;
	void* tmp_ptr = nullptr;

	using T = typename std::remove_reference<ValuesRange>::type::value_type;

	auto exec = [&] {
		cuda::throw_if_error(cub::DeviceSelect::If(tmp_ptr,
		                                           tmp_bytes_size,
		                                           values.data(),
		                                           selected.data(),
		                                           num_selected_ptr,
		                                           N,
		                                           select_op,
		                                           stream.handle()));
	};
	exec();
	auto tmp =
	    make_not_a_vector<uint8_t>(tmp_bytes_size, delayed_memory_resource);
	tmp_ptr = tmp.to_span().data();
	exec();
}

template <class ValuesIt,
          class SelectedIt,
          class NumSelectedPtr,
          class SelectOp,
          class MemoryResource>
void select_if(cuda::stream_t& stream,
               ValuesIt values,
               SelectedIt selected,
               NumSelectedPtr num_selected_ptr,
               size_t N,
               SelectOp select_op,
               MemoryResource& delayed_memory_resource) {

	size_t tmp_bytes_size = 0;
	void* tmp_ptr = nullptr;

	auto exec = [&] {
		cuda::throw_if_error(cub::DeviceSelect::If(tmp_ptr,
		                                           tmp_bytes_size,
		                                           values,
		                                           selected,
		                                           num_selected_ptr,
		                                           N,
		                                           select_op,
		                                           stream.handle()));
	};
	exec();
	auto tmp =
	    make_not_a_vector<uint8_t>(tmp_bytes_size, delayed_memory_resource);
	tmp_ptr = tmp.to_span().data();
	exec();
}

/*! \brief Select values based on predicate with their index.
 *
 *  \param values Range of length N with value_type `T`
 *  \param selected Range of length N with a value type which is assignable
 *      by a thrust::tuple<T, int>.
 *  \param select_op select predicate with signature
 *      ```
 *      select_op = [] __device__ (const thrust::tuple<T, int>& tup) { ... };
 *      ```
 */
template <class ValuesRange,
          class SelectedRange,
          class NumSelectedPtr,
          class SelectOp,
          class MemoryResource>
void select_if_with_index(cuda::stream_t& stream,
                          ValuesRange&& values,
                          SelectedRange&& selected,
                          NumSelectedPtr num_selected_ptr,
                          SelectOp select_op,
                          MemoryResource& delayed_memory_resource) {

	const std::size_t N = values.size();

	gsl_Expects(selected.size() == N);

	size_t tmp_bytes_size = 0;
	void* tmp_ptr = nullptr;

	using T = typename std::remove_reference<ValuesRange>::type::value_type;

	auto cit = thrust::make_counting_iterator(0);
	auto it = thrust::make_zip_iterator(thrust::make_tuple(values.data(), cit));

	auto exec = [&] {
		cuda::throw_if_error(cub::DeviceSelect::If(tmp_ptr,
		                                           tmp_bytes_size,
		                                           it,
		                                           selected.data(),
		                                           num_selected_ptr,
		                                           N,
		                                           select_op,
		                                           stream.handle()));
	};
	exec();
	auto tmp =
	    make_not_a_vector<uint8_t>(tmp_bytes_size, delayed_memory_resource);
	tmp_ptr = tmp.to_span().data();
	exec();
}

template <class ValuesRange,
          class SelectedRange,
          class SelectedIndexRange,
          class NumSelectedPtr,
          class SelectOp,
          class MemoryResource>
void select_if_with_index(cuda::stream_t& stream,
                          ValuesRange&& values,
                          SelectedRange&& selected,
                          SelectedIndexRange&& selected_indices,
                          NumSelectedPtr num_selected_ptr,
                          SelectOp select_op,
                          MemoryResource& delayed_memory_resource) {

	const std::size_t N = values.size();

	gsl_Expects(selected.size() == N);

	size_t tmp_bytes_size = 0;
	void* tmp_ptr = nullptr;

	using T = typename std::remove_reference<ValuesRange>::type::value_type;

	auto cit = thrust::make_counting_iterator(0);
	auto it = thrust::make_zip_iterator(thrust::make_tuple(values.data(), cit));
	auto result_it = thrust::make_zip_iterator(
	    thrust::make_tuple(selected.data(), selected_indices.data()));

	auto exec = [&] {
		cuda::throw_if_error(cub::DeviceSelect::If(tmp_ptr,
		                                           tmp_bytes_size,
		                                           it,
		                                           result_it,
		                                           num_selected_ptr,
		                                           N,
		                                           select_op,
		                                           stream.handle()));
	};
	exec();
	auto tmp =
	    make_not_a_vector<uint8_t>(tmp_bytes_size, delayed_memory_resource);
	tmp_ptr = tmp.to_span().data();
	exec();
}

} // namespace async

} // namespace thrustshift


#ifndef ARRUS_COMMON_FORMAT_H
#define ARRUS_COMMON_FORMAT_H

// String formatting and parsing utilities.
// Currently wraps fmt library calls.
#include <fmt/format.h>
#include <stdexcept>
#include <cctype>
#include <vector>
#include <set>
#include <unordered_set>
#include <optional>
#include <sstream>
#include <gsl/span>

#include <boost/algorithm/string/join.hpp>

#include "arrus/core/api/common/Tuple.h"
#include "arrus/core/api/common/Interval.h"

namespace arrus {

template<typename... Args>
auto format(Args &&... args) {
    return fmt::format(std::forward<Args>(args)...);
}

/**
 * Returns true if the given string contains numeric characters only.
 *
 * @param num string to verify
 * @return true if the given string contains numeric characters only,
 *         false otherwise.
 */
inline bool isDigitsOnly(const std::string &num) {
    return std::all_of(num.begin(), num.end(), isdigit);
}

/**
 * General purpose 'toString' function basing on ostream << operator.
 */
template<typename T>
std::string toString(const T &t)  {
    std::ostringstream ss;
    ss << t;
    return ss.str();
}

template<typename T>
inline std::string toString(const std::vector<T> &values) {
    std::vector<std::string> vStr(values.size());
    std::transform(std::begin(values), std::end(values), std::begin(vStr),
                   [](auto v) { return std::to_string(v); });
    return boost::algorithm::join(vStr, ", ");
}

template<typename T>
inline std::string toString(
        const gsl::span<T> &values) {
    std::vector<std::string> vStr(values.size());
    std::transform(std::begin(values), std::end(values), std::begin(vStr),
                   [](auto v) { return std::to_string(v); });
    return boost::algorithm::join(vStr, ", ");
}

template<typename T>
inline std::string toStringTransform(
        const std::vector<T> &values,
        const std::function<std::string(const T&)> &func) {
    std::vector<std::string> vStr(values.size());
    std::transform(std::begin(values), std::end(values), std::begin(vStr),
                   [&func](T v) { return func(v); });
    return boost::algorithm::join(vStr, ", ");
}

template<typename T>
inline std::string toString(const ::std::set<T> &values) {
    std::vector<std::string> vStr(values.size());
    std::transform(std::begin(values), std::end(values), std::begin(vStr),
                   [](auto v) { return std::to_string(v); });
    return boost::algorithm::join(vStr, ", ");
}

template<typename T>
inline std::string toString(const ::std::unordered_set<T> &values) {
    std::vector<std::string> vStr(values.size());
    std::transform(std::begin(values), std::end(values), std::begin(vStr),
                   [](auto v) { return std::to_string(v); });
    return boost::algorithm::join(vStr, ", ");
}

template<typename T>
inline std::string toString(const std::optional<T> value) {
    if(value.has_value()) {
        return std::to_string(value.value());
    } else return "(no value)";
}

template<typename T>
inline std::string toString(const Tuple<T> tuple) {
    return ::arrus::format("Tuple({})", toString(tuple.getValues()));
}

template<typename T>
inline std::string toString(const Interval<T> i) {
    return ::arrus::format("Interval: start: {}, right: {}",
                           i.start(), i.end());
}

}

#endif //ARRUS_COMMON_FORMAT_H


// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#ifndef _HEBench_ClearText_BE_DataPack_H_7e5fa8c2415240ea93eff148ed73539b
#define _HEBench_ClearText_BE_DataPack_H_7e5fa8c2415240ea93eff148ed73539b

#include <memory>
#include <vector>

#include <gsl/gsl>

#include "clear_error.h"

#include "hebench/api_bridge/types.h"

#include "hebench/api_bridge/cpp/hebench.hpp"

template <class T>
/**
 * @brief Encapsulates a HEBench DataPack.
 */
class ClearDataPack : public hebench::cpp::ITaggedObject
{
private:
    HEBERROR_DECLARE_CLASS_NAME(ClearDataPack)

public:
    explicit ClearDataPack(const hebench::APIBridge::DataPack &data_pack);
    /**
     * @brief Creates a new data pack with specified data sizes.
     * @param sample_count[in] Number of data samples to be contained in this pack.
     * @param p_sample_sizes[in] List of number of items per data sample.
     * @param position[in] Parameter position corresponding to hebench::APIBridge::DataPack::param_position.
     * @details This constructor initializes vector<vector<T>> data structure of the shape
     * @code
     * data = vector<vector<T>>(sample_count)
     * @endcode
     * and
     * @code
     * data[i] = vector<T>(p_sample_sizes[i])
     * @endcode
     */
    explicit ClearDataPack(std::uint64_t sample_count,
                           const std::uint64_t *p_sample_sizes,
                           std::uint64_t position);
    ~ClearDataPack() override {}

    /**
     * @brief Fills pre-allocated HEBench data pack with the data contained in this
     * data pack.
     * @param data_pack[out] HEBench data pack where to store the data.
     * @param b_pad[in] If true, any extra space in \p data_pack will be padded with
     * zeroes. Otherwise, extra space will not be overwritten.
     * @details This method is the inverse of the constructor. Thus, if the constructor
     * performs some type of conversion, it must be reversible, and this method
     * reverses the conversion.
     *
     * Default implementation is a simple copy of the data.
     */
    virtual void fillHEBenchDataPack(hebench::APIBridge::DataPack &data_pack, bool b_pad) const;

    std::uint64_t getSamplesCount() const { return m_data.size(); }
    gsl::span<T> getSample(std::uint64_t sample_index);
    gsl::span<const T> getSample(std::uint64_t sample_index) const;
    /**
     * @brief Copies the data contained in \p sample_data into this data pack's
     * sample specified by \p sample index.
     * @param sample_index[in] Index of data sample in this data pack to overwrite.
     * @param sample_data[in] Data to copy into this data pack sample.
     * @details The size of this data pack sample will be resized to match the
     * size of specified \p sample-data.
     */
    void setSample(std::uint64_t sample_index, const gsl::span<T> &sample_data);
    /**
     * @brief Copies the data contained in \p sample_data into this data pack's
     * sample specified by \p sample index.
     * @param sample_index[in] Index of data sample in this data pack to overwrite.
     * @param sample_data[in] Data to copy into this data pack sample.
     * @param pad_value[in] Value to be used for padding if needed.
     * @details The size of this data pack sample will remain constant. If not
     * enough space, this method will copy as much data as it can from \p sample_data
     * into the specified sample. If this data pack's sample's size is more than
     * the supplied data in \p sample_data, the remaining space will be padded
     * with the specified padding value \p pad_value.
     */
    void setSample(std::uint64_t sample_index, const gsl::span<T> &sample_data, const T &pad_value);

    std::uint64_t position() const { return m_position; }

protected:
    std::vector<std::vector<T>> m_data;

    ClearDataPack(std::uint64_t position = 0) :
        m_position(position) {}
    void allocateBuffers(std::uint64_t sample_count, const std::uint64_t *p_sample_sizes);
    void allocateBuffers(const hebench::APIBridge::DataPack &data_pack);
    /**
     * @brief Performs a simple copy.
     * @param data_pack
     */
    virtual void fillFromHEBenchDataPack(const hebench::APIBridge::DataPack &data_pack);

private:
    std::uint64_t m_position;
};

#include "inl/data_container.inl"

#endif // defined _HEBench_ClearText_BE_DataPack_H_7e5fa8c2415240ea93eff148ed73539b


#pragma once
#include <Hypo/System/Exports.h>
#include <Hypo/Config.h>
#include <ostream>
#include <gsl/span>
#include <Hypo/System/Exports.h>

#include <Hypo/System/Buffer/Buffer.h>
#include <Hypo/System/Streams/MemoryStream.h>

namespace Hypo
{
	class HYPO_SYSTEM_API BinaryWriter
	{
	public:
		BinaryWriter(std::ostream& stream);

		BinaryWriter& operator <<(uInt8 value);
		BinaryWriter& operator <<(uInt16 value);
		BinaryWriter& operator <<(uInt32 value);
		BinaryWriter& operator <<(uInt64 value);

		BinaryWriter& operator <<(Int8 value);
		BinaryWriter& operator <<(Int16 value);
		BinaryWriter& operator <<(Int32 value);
		BinaryWriter& operator <<(Int64 value);

		BinaryWriter& operator <<(const std::string& value);
		BinaryWriter& operator <<(const char* value);

		template<typename T>
		BinaryWriter& operator <<(const std::vector<T>& value)
		{
			const uInt32 size(static_cast<uInt32>(value.size()));
			*this << size;
			for (auto& element : value)
			{
				*this << element;
			}
			return *this;
		}

		void WriteRaw(const std::string& data);
		void WriteRaw(const gsl::span<uInt8>& data);
		void WriteRaw(const void* data, int size);

		void WriteBOM();

		void Write7BitEncoded(uInt32 value);
		void Write7BitEncoded(uInt64 value);

		void Flush()const { m_Stream.flush(); }
		bool Good()const { return m_Stream.good(); }
		bool Bad()const { return m_Stream.bad(); }
		bool Fail() const { return m_Stream.fail(); }

		std::ostream& GetStream() const {return m_Stream;}
	private:
		std::ostream& m_Stream;
	};

	template <typename T>
	class BasicMemoryBinaryWriter : public BinaryWriter
		/// A convenient wrapper for using Buffer and MemoryStream with BinarWriter.
	{
	public:
		BasicMemoryBinaryWriter(Buffer<T>& data) :
			BinaryWriter(_ostr),
			_data(data),
			_ostr(data.begin(), data.Capacity())
		{
		}

		~BasicMemoryBinaryWriter()
		{
			try
			{
				Flush();
			}
			catch (...)
			{
			}
		}

		Buffer<T>& data()
		{
			return _data;
		}

		const Buffer<T>& data() const
		{
			return _data;
		}

		const MemoryOutputStream& stream() const
		{
			return _ostr;
		}

		MemoryOutputStream& stream()
		{
			return _ostr;
		}

	private:
		Buffer<T>& _data;
		MemoryOutputStream _ostr;
	};

	typedef BasicMemoryBinaryWriter<char> MemoryBinaryWriter;

}


#pragma once
#include <gsl/gsl_vector.h>
#include "BooleanNodes.h"
#include "BooleanDAG.h"
#include <map>
#include "SymbolicEvaluator.h"
#include "ConflictGenerator.h"

#include <iostream>
#include "Util.h"

class SmartConflictGenerator: public ConflictGenerator {
	SymbolicEvaluator* eval;
	map<int, int>& imap;
	BooleanDAG* dag;
	set<int>& ignoredBoolNodes;
	set<int>& ctrlNodes;

	vector<set<int>> dependentInputs;
	vector<set<int>> dependentCtrls;

public:
	ConflictGenerator(SymbolicEvaluator* eval_, map<int, int>& imap_, BooleanDAG* dag_, set<int>& ignoredBoolNodes_, set<int>& ctrlNodes_): eval(eval_), imap(imap_), dag(dag_), ignoredBoolNodes(ignoredBoolNodes_), ctrlNodes(ctrlNodes_) {
		// process the dag and collect dependencies
		for (BooleanDAG::iterator node_it = dag->begin(); node_it != dag->end(); ++node_it) {
			bool_node* n = *node_it;
			set<int> inputs; set<int> ctrls;

			const vector<bool_node*>& parents = n->parents();
			for (int i = 0; i < parents.size(); i++) {
				bool_node* parent = parents[i];
				set<int>& parentInputs = dependentInputs[parent->id];
				set<int>& parentCtrls = dependentCtrls[parent->id];
				if (parent->getOtype() == OutType::BOOL) {
					if (ignoredBoolNodes.find(parent->id) == ignoredBoolNodes.end()) {
						inputs.insert(parent->id);
						//inputs.insert(parentInputs.begin(), parentInputs.end());
					}
				} else {
					inputs.insert(parentInputs.begin(), parentInputs.end());
					ctrls.insert(parentCtrls.begin(), parentCtrls.end());
				}

				if (ctrlNodes.find(parent->id) != ctrlNodes.end()) {
					ctrls.insert(parent->id);
				}
			}
			dependentInputs.push_back(inputs);
			dependentCtrls.push_back(ctrls);
		}

	}

	bool isConflict(set<int> influentialControls, set<int> myControls) {
		for (int i : influentialControls) {
			if (myControls.find(i) != myControls.end()) {
				return true;
			}
		}
		return false;
	}

	virtual vector<pair<int, int>> getConflicts(gsl_vector* state, vector<vector<int>>& allInputs, vector<int>& instanceIds, int rowid, int colid) {
		vector<pair<int, int>> conflicts;
		for (int i = 0; i < allInputs.size(); i++) {
			const map<int, int>& nodeValsMap = Util::getNodeToValMap(imap, allInputs[i]);
			eval->run(state, nodeValsMap);

			// First, find a failing node
			bool_node* failedNode = NULL;
			for (BooleanDAG::iterator node_it = dag->begin(); node_it != dag->end(); ++node_it) {
				bool_node* n = *node_it;
				if (n->type == bool_node::ASSERT) {
					if (!eval->check(n->mother, 1)) {
						failedNode = n;
						break;
					}
				}
				if (n->getOtype() == OutType::BOOL) {
					auto it = nodeValsMap.find(n->id);
					if (it != nodeValsMap.end()) {
						int val = it->second;
						if (!eval->check(n, val)) {
							failedNode = n;
							break;
						}
					}
				}
			}

			Assert(failedNode != NULL, "No conflict?");
			cout << failedNode->lprint() << endl;
			set<int> conflictNodes;
			// First, add all dependent inputs
			set<int>& depInputs = dependentInputs[failedNode->id];
			conflictNodes.insert(depInputs.begin(), depInputs.end());
			cout << "Dep inputs:" << endl;
			for (auto it = depInputs.begin(); it != depInputs.end(); it++) {
				cout << (*dag)[(*it)]->lprint() << endl;
			}

			set<int>& depCtrls = dependentCtrls[failedNode->id];
			cout << "Dep ctrls:" << endl;
			for (auto it = depCtrls.begin(); it != depCtrls.end(); it++) {
				cout << (*dag)[(*it)]->lprint() << endl;
			}
			// Next, collect all boolean nodes that are influenced by the controls that affect the failed node
			for (BooleanDAG::iterator node_it = dag->begin(); node_it != dag->end(); ++node_it) {
				bool_node* n = *node_it;
				if (n->type == bool_node::ASSERT) {
					if (isConflict(depCtrls, dependentCtrls[n->id])) {
						conflictNodes.insert(n->id);
					}
				}
				if (n->getOtype() == OutType::BOOL) {
					if (isConflict(depCtrls, dependentCtrls[n->id])) {
						conflictNodes.insert(n->id);
					}
				}
			}

			cout << "Final conflict nodes" << endl;

			//conflictNodes.insert(colid);

			// Process the conflicts
			for (int j = 0; j < imap.size(); j++) {
				if (allInputs[i][j] != EMPTY) {
					if (ignoredBoolNodes.find(imap[j]) == ignoredBoolNodes.end()) {
						if (imap[j] < 0 || conflictNodes.find(imap[j]) != conflictNodes.end()) {
							if (imap[j] >= 0) {
								cout << (*dag)[imap[j]]->lprint() << " " << allInputs[i][j] << endl;
							}
							conflicts.push_back(make_pair(instanceIds[i], j));
						}
					}
				}
			}
		}
		return conflicts;
	}

};


#pragma once

#include <iostream>

#include <gsl/gsl.h>

namespace util{
template<typename T>
void print(T const&x){
    std::cerr <<x << " ";
}

template<typename T, int64_t M>
void print(gsl::span<T,M> const span){
    for(auto x : span) print(x);
    std::cerr << " :1D"<<std::endl;
}

template<typename T, int64_t M,int64_t N>
void print(gsl::span<T,M,N> const span){
    ////ranged for iterates flattened span.
    //for(auto x : span) print(x);
    for(int64_t i=0; i<M; ++i) print(span[i]);
    std::cerr << " :2D static"<<std::endl;
}

template<typename T, int64_t M,int64_t N>
void print(gsl::span<const T,gsl::dynamic_range,M,N> span){
    for(int64_t i=0; i<M; ++i) print(span[i]);
    //for(auto it=span.cbegin(); it<span.cend(); ++it) print_span(*it);
    std::cerr << " :2D dynamic_range"<<std::endl;
}
// template<typename T>
// void print(std::vector<T> const & vec){
//     print(gsl::as_span(vec));
// }
// template<typename T, size_t M>
// void print(std::array<T,M> arr){
//     print(gsl::as_span(arr));
// }

}//namespcae util


#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <gbpLib.h>
#include <gbpRNG.h>
#include <gbpMCMC.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_fit.h>
#include <gsl/gsl_interp.h>

void free_MCMC(MCMC_info *MCMC) {
    int           i_P, i_DS;
    int           i_array;
    MCMC_DS_info *current_DS;
    MCMC_DS_info *next_DS;

    SID_log("Freeing MCMC structure...", SID_LOG_OPEN);

    // Parameter arrays
    for(i_P = 0; i_P < MCMC->n_P; i_P++)
        SID_free(SID_FARG MCMC->P_names[i_P]);
    SID_free(SID_FARG MCMC->P_names);
    SID_free(SID_FARG MCMC->P_init);
    SID_free(SID_FARG MCMC->P_new);
    SID_free(SID_FARG MCMC->P_last);
    SID_free(SID_FARG MCMC->P_chain);
    SID_free(SID_FARG MCMC->P_limit_min);
    SID_free(SID_FARG MCMC->P_limit_max);
    if(MCMC->n_arrays > 0) {
        for(i_array = 0; i_array < MCMC->n_arrays; i_array++) {
            SID_free(SID_FARG MCMC->array[i_array]);
            SID_free(SID_FARG MCMC->array_name[i_array]);
        }
        SID_free(SID_FARG MCMC->array);
        SID_free(SID_FARG MCMC->array_name);
    }

    // Covariance and displacement vector
    free_MCMC_covariance(MCMC);

    // Random number generator
    if(MCMC->RNG != NULL)
        free_RNG(MCMC->RNG);

    // Dataset arrays
    free_MCMC_arrays(MCMC);
    free_MCMC_DS(MCMC);

    // Communicators
    SID_Comm_free(&(MCMC->comm));

    SID_log("Done.", SID_LOG_CLOSE);
}


/* matrix/gsl_matrix_short.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_MATRIX_SHORT_H__
#define __GSL_MATRIX_SHORT_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_vector_short.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 size1;
  size_t size2;
  size_t tda;
  short * data;
  gsl_block_short * block;
  int owner;
} gsl_matrix_short;

typedef struct
{
  gsl_matrix_short matrix;
} _gsl_matrix_short_view;

typedef _gsl_matrix_short_view gsl_matrix_short_view;

typedef struct
{
  gsl_matrix_short matrix;
} _gsl_matrix_short_const_view;

typedef const _gsl_matrix_short_const_view gsl_matrix_short_const_view;

/* Allocation */

GSL_FUN gsl_matrix_short *
gsl_matrix_short_alloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_short *
gsl_matrix_short_calloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_short *
gsl_matrix_short_alloc_from_block (gsl_block_short * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

GSL_FUN gsl_matrix_short *
gsl_matrix_short_alloc_from_matrix (gsl_matrix_short * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN gsl_vector_short *
gsl_vector_short_alloc_row_from_matrix (gsl_matrix_short * m,
                                        const size_t i);

GSL_FUN gsl_vector_short *
gsl_vector_short_alloc_col_from_matrix (gsl_matrix_short * m,
                                        const size_t j);

GSL_FUN void gsl_matrix_short_free (gsl_matrix_short * m);

/* Views */

GSL_FUN _gsl_matrix_short_view
gsl_matrix_short_submatrix (gsl_matrix_short * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_short_view
gsl_matrix_short_row (gsl_matrix_short * m, const size_t i);

GSL_FUN _gsl_vector_short_view
gsl_matrix_short_column (gsl_matrix_short * m, const size_t j);

GSL_FUN _gsl_vector_short_view
gsl_matrix_short_diagonal (gsl_matrix_short * m);

GSL_FUN _gsl_vector_short_view
gsl_matrix_short_subdiagonal (gsl_matrix_short * m, const size_t k);

GSL_FUN _gsl_vector_short_view
gsl_matrix_short_superdiagonal (gsl_matrix_short * m, const size_t k);

GSL_FUN _gsl_vector_short_view
gsl_matrix_short_subrow (gsl_matrix_short * m, const size_t i,
                         const size_t offset, const size_t n);

GSL_FUN _gsl_vector_short_view
gsl_matrix_short_subcolumn (gsl_matrix_short * m, const size_t j,
                            const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_short_view
gsl_matrix_short_view_array (short * base,
                             const size_t n1,
                             const size_t n2);

GSL_FUN _gsl_matrix_short_view
gsl_matrix_short_view_array_with_tda (short * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_FUN _gsl_matrix_short_view
gsl_matrix_short_view_vector (gsl_vector_short * v,
                              const size_t n1,
                              const size_t n2);

GSL_FUN _gsl_matrix_short_view
gsl_matrix_short_view_vector_with_tda (gsl_vector_short * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_FUN _gsl_matrix_short_const_view
gsl_matrix_short_const_submatrix (const gsl_matrix_short * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_short_const_view
gsl_matrix_short_const_row (const gsl_matrix_short * m,
                            const size_t i);

GSL_FUN _gsl_vector_short_const_view
gsl_matrix_short_const_column (const gsl_matrix_short * m,
                               const size_t j);

GSL_FUN _gsl_vector_short_const_view
gsl_matrix_short_const_diagonal (const gsl_matrix_short * m);

GSL_FUN _gsl_vector_short_const_view
gsl_matrix_short_const_subdiagonal (const gsl_matrix_short * m,
                                    const size_t k);

GSL_FUN _gsl_vector_short_const_view
gsl_matrix_short_const_superdiagonal (const gsl_matrix_short * m,
                                      const size_t k);

GSL_FUN _gsl_vector_short_const_view
gsl_matrix_short_const_subrow (const gsl_matrix_short * m, const size_t i,
                               const size_t offset, const size_t n);

GSL_FUN _gsl_vector_short_const_view
gsl_matrix_short_const_subcolumn (const gsl_matrix_short * m, const size_t j,
                                  const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_short_const_view
gsl_matrix_short_const_view_array (const short * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_FUN _gsl_matrix_short_const_view
gsl_matrix_short_const_view_array_with_tda (const short * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_FUN _gsl_matrix_short_const_view
gsl_matrix_short_const_view_vector (const gsl_vector_short * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN _gsl_matrix_short_const_view
gsl_matrix_short_const_view_vector_with_tda (const gsl_vector_short * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_FUN void gsl_matrix_short_set_zero (gsl_matrix_short * m);
GSL_FUN void gsl_matrix_short_set_identity (gsl_matrix_short * m);
GSL_FUN void gsl_matrix_short_set_all (gsl_matrix_short * m, short x);

GSL_FUN int gsl_matrix_short_fread (FILE * stream, gsl_matrix_short * m) ;
GSL_FUN int gsl_matrix_short_fwrite (FILE * stream, const gsl_matrix_short * m) ;
GSL_FUN int gsl_matrix_short_fscanf (FILE * stream, gsl_matrix_short * m);
GSL_FUN int gsl_matrix_short_fprintf (FILE * stream, const gsl_matrix_short * m, const char * format);

GSL_FUN int gsl_matrix_short_memcpy(gsl_matrix_short * dest, const gsl_matrix_short * src);
GSL_FUN int gsl_matrix_short_swap(gsl_matrix_short * m1, gsl_matrix_short * m2);

GSL_FUN int gsl_matrix_short_swap_rows(gsl_matrix_short * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_short_swap_columns(gsl_matrix_short * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_short_swap_rowcol(gsl_matrix_short * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_short_transpose (gsl_matrix_short * m);
GSL_FUN int gsl_matrix_short_transpose_memcpy (gsl_matrix_short * dest, const gsl_matrix_short * src);

GSL_FUN short gsl_matrix_short_max (const gsl_matrix_short * m);
GSL_FUN short gsl_matrix_short_min (const gsl_matrix_short * m);
GSL_FUN void gsl_matrix_short_minmax (const gsl_matrix_short * m, short * min_out, short * max_out);

GSL_FUN void gsl_matrix_short_max_index (const gsl_matrix_short * m, size_t * imax, size_t *jmax);
GSL_FUN void gsl_matrix_short_min_index (const gsl_matrix_short * m, size_t * imin, size_t *jmin);
GSL_FUN void gsl_matrix_short_minmax_index (const gsl_matrix_short * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

GSL_FUN int gsl_matrix_short_isnull (const gsl_matrix_short * m);
GSL_FUN int gsl_matrix_short_ispos (const gsl_matrix_short * m);
GSL_FUN int gsl_matrix_short_isneg (const gsl_matrix_short * m);
GSL_FUN int gsl_matrix_short_isnonneg (const gsl_matrix_short * m);

GSL_FUN int gsl_matrix_short_add (gsl_matrix_short * a, const gsl_matrix_short * b);
GSL_FUN int gsl_matrix_short_sub (gsl_matrix_short * a, const gsl_matrix_short * b);
GSL_FUN int gsl_matrix_short_mul_elements (gsl_matrix_short * a, const gsl_matrix_short * b);
GSL_FUN int gsl_matrix_short_div_elements (gsl_matrix_short * a, const gsl_matrix_short * b);
GSL_FUN int gsl_matrix_short_scale (gsl_matrix_short * a, const double x);
GSL_FUN int gsl_matrix_short_add_constant (gsl_matrix_short * a, const double x);
GSL_FUN int gsl_matrix_short_add_diagonal (gsl_matrix_short * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_FUN int gsl_matrix_short_get_row(gsl_vector_short * v, const gsl_matrix_short * m, const size_t i);
GSL_FUN int gsl_matrix_short_get_col(gsl_vector_short * v, const gsl_matrix_short * m, const size_t j);
GSL_FUN int gsl_matrix_short_set_row(gsl_matrix_short * m, const size_t i, const gsl_vector_short * v);
GSL_FUN int gsl_matrix_short_set_col(gsl_matrix_short * m, const size_t j, const gsl_vector_short * v);
/***********************************************************************/

/* inline functions if you are using GCC */

GSL_FUN INLINE_DECL short   gsl_matrix_short_get(const gsl_matrix_short * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL void    gsl_matrix_short_set(gsl_matrix_short * m, const size_t i, const size_t j, const short x);
GSL_FUN INLINE_DECL short * gsl_matrix_short_ptr(gsl_matrix_short * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL const short * gsl_matrix_short_const_ptr(const gsl_matrix_short * m, const size_t i, const size_t j);

#ifdef HAVE_INLINE
INLINE_FUN
short
gsl_matrix_short_get(const gsl_matrix_short * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_VAL("first index out of range", GSL_EINVAL, 0) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VAL("second index out of range", GSL_EINVAL, 0) ;
        }
    }
#endif
  return m->data[i * m->tda + j] ;
}

INLINE_FUN
void
gsl_matrix_short_set(gsl_matrix_short * m, const size_t i, const size_t j, const short x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_VOID("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VOID("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  m->data[i * m->tda + j] = x ;
}

INLINE_FUN
short *
gsl_matrix_short_ptr(gsl_matrix_short * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (short *) (m->data + (i * m->tda + j)) ;
}

INLINE_FUN
const short *
gsl_matrix_short_const_ptr(const gsl_matrix_short * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (const short *) (m->data + (i * m->tda + j)) ;
}

#endif

__END_DECLS

#endif /* __GSL_MATRIX_SHORT_H__ */


/* ****************************************************************** **
**    OpenSees - Open System for Earthquake Engineering Simulation    **
**          Pacific Earthquake Engineering Research Center            **
**                                                                    **
**                                                                    **
** (C) Copyright 1999, The Regents of the University of California    **
** All Rights Reserved.                                               **
**                                                                    **
** Commercial use of this program without express permission of the   **
** University of California, Berkeley, is strictly prohibited.  See   **
** file 'COPYRIGHT'  in main directory for information on usage and   **
** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
**                                                                    **
** Developed by:                                                      **
**   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
**   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
**   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
**                                                                    **
** ****************************************************************** */

// $Revision: 1.2 $
// $Date: 2007-02-14 20:12:32 $
// $Source: /usr/local/cvs/OpenSees/SRC/system_of_eqn/linearSOE/petsc/ShadowPetscSOE.h,v $

// File: ~/system_of_eqn/linearSOE/petsc/ShadowPetscSOE.h
//
// Written: fmk & om
// Created: 7/98
// Revision: A
//
// Description: This file contains the class definition for ShadowPetscSOE
// ShadowPetscSOE is a subclass of LinearSOE.

// What: "@(#) ShadowPetscSOE.h, revA"

#ifndef ShadowPetscSOE_h
#define ShadowPetscSOE_h

#include <LinearSOE.h>
#include <Vector.h>
#include <PetscSOE.h>

extern "C" {
#include <petsc.h>
}

class PetscSolver;

class ShadowPetscSOE : public LinearSOE
{
  public:
    ShadowPetscSOE(PetscSolver &theSolver, int blockSize);

    ~ShadowPetscSOE();

    int solve(void);

    int getNumEqn(void) const;
    int setSize(Graph &theGraph);

    int addA(const Matrix &, const ID &, double fact = 1.0);
    int addB(const Vector &, const ID &, double fact = 1.0);
    int setB(const Vector &, double fact = 1.0);

    void zeroA(void);
    void zeroB(void);

    const Vector &getX(void);
    const Vector &getB(void);
    double normRHS(void);

    void setX(int loc, double value);

    int setSolver(PetscSolver &newSolver);

    int sendSelf(int commitTag, Channel &theChannel);
    int recvSelf(int commitTag, Channel &theChannel,
		 FEM_ObjectBroker &theBroker);

  protected:

  private:
    MPI_Comm theComm; // a comm for communicating to the ActorPetscSOE's
                      // without using PETSC_COMM_WORLD
    PetscSOE theSOE;  // the local portion of the SOE
    PetscSolver *theSolver; // created by the user
    int myRank;
    int numProcessors;
    int sendData[3];
    void *sendBuffer;
    int blockSize;
};

#endif


/*
FRACTAL - A program growing fractals to benchmark parallelization and drawing
libraries.

Copyright 2009-2021, Javier Burguete Tolosa.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

2. 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.

THIS SOFTWARE IS PROVIDED BY Javier Burguete Tolosa ``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 Javier Burguete Tolosa 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.
*/

/**
 * \file graphic.c
 * \brief Source file to define the graphic drawing data and functions.
 * \author Javier Burguete Tolosa.
 * \copyright Copyright 2009-2021, Javier Burguete Tolosa.
 */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <gsl/gsl_rng.h>
#include <glib.h>
#include <png.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <gtk/gtk.h>
#include <GL/glew.h>

#include "config.h"
#include "fractal.h"
#include "image.h"
#include "text.h"
#include "graphic.h"

unsigned int window_width = 480;        ///< Graphic window width.
unsigned int window_height = 480;       ///< Graphic window height.

/**
 * Function to init the graphic data.

 * \return 1 on success, 0 on error.
 */
int
graphic_init (Graphic * graphic,        ///< Draw struct.
              char *logo_name)  ///< Logo PNG file name.
{
  const GLfloat projection_matrix[16] = {
    1., 0., 0., 0.,
    0, 1., 0., 0.,
    0., 0, 0., 0.,
    0., 0., 0., 1.
  };
  const char *vs_3D_source =
    "attribute highp vec3 position;"
    "attribute lowp vec3 color;"
    "varying lowp vec3 fcolor;"
    "uniform highp mat4 matrix;"
    "void main ()"
    "{gl_Position = matrix * vec4 (position, 1.f); fcolor = color;}";
  const char *fs_source =
    "varying lowp vec3 fcolor;"
    "void main () {gl_FragColor = vec4 (fcolor, 1.f);}";
  const char *vertex_name = "position";
  const char *color_name = "color";
  const char *matrix_name = "matrix";
  // GLSL version
  const char *version = "#version 120\n";       // OpenGL 2.1
  const char *vs_3D_sources[3] = { version, INIT_GL_GLES, vs_3D_source };
  const char *fs_sources[3] = { version, INIT_GL_GLES, fs_source };
  const char *error_message;
  GLint k;
  GLuint vs, fs;
  GLenum glew_status;

#if DEBUG
  printf ("graphic_init: start\n");
  fflush (stdout);
#endif

  // Initing GLEW
#if DEBUG
  printf ("Initing GLEW\n");
  fflush (stdout);
#endif
  glew_status = glewInit ();
  if (glew_status != GLEW_OK)
    {
      printf ("ERROR! glewInit: %s\n", glewGetErrorString (glew_status));
      return 0;
    }

#if DEBUG
  printf ("graphic_init: compiling fragment shader\n");
  fflush (stdout);
#endif
  fs = glCreateShader (GL_FRAGMENT_SHADER);
  glShaderSource (fs, 3, fs_sources, NULL);
  glCompileShader (fs);
  glGetShaderiv (fs, GL_COMPILE_STATUS, &k);
  if (!k)
    {
      error_message = "unable to compile the fragment shader";
      goto exit_on_error;
    }

#if DEBUG
  printf ("graphic_init: compiling 3D vertex shader\n");
  fflush (stdout);
#endif
  vs = glCreateShader (GL_VERTEX_SHADER);
  glShaderSource (vs, 3, vs_3D_sources, NULL);
  glCompileShader (vs);
  glGetShaderiv (vs, GL_COMPILE_STATUS, &k);
  if (!k)
    {
      glDeleteShader (fs);
      error_message = "unable to compile the 3D vertex shader";
      goto exit_on_error;
    }

  graphic->program_3D = glCreateProgram ();
  glAttachShader (graphic->program_3D, vs);
  glAttachShader (graphic->program_3D, fs);
  glLinkProgram (graphic->program_3D);
  glDeleteShader (vs);
  glDeleteShader (fs);
  glGetProgramiv (graphic->program_3D, GL_LINK_STATUS, &k);
  if (!k)
    {
      error_message = "unable to link the program 3D";
      goto exit_on_error;
    }

  graphic->attribute_3D_position
    = glGetAttribLocation (graphic->program_3D, vertex_name);
  if (graphic->attribute_3D_position == -1)
    {
      error_message = "could not bind attribute";
      goto exit_on_error;
    }

  graphic->attribute_3D_color
    = glGetAttribLocation (graphic->program_3D, color_name);
  if (graphic->attribute_3D_color == -1)
    {
      error_message = "could not bind attribute";
      goto exit_on_error;
    }

  graphic->uniform_3D_matrix
    = glGetUniformLocation (graphic->program_3D, matrix_name);
  if (graphic->uniform_3D_matrix == -1)
    {
      error_message = "could not bind uniform";
      goto exit_on_error;
    }

  memcpy (graphic->projection_matrix, projection_matrix, 16 * sizeof (GLfloat));

#if DEBUG
  printf ("graphic_init: initing logo\n");
  fflush (stdout);
#endif
  if (logo_name)
    {
      graphic->logo = image_new (logo_name);
      if (!graphic->logo)
        {
          error_message = "unable to open the logo";
          goto exit_on_error;
        }
      if (!image_init (graphic->logo))
        {
          error_message = "unable to init the logo";
          goto exit_on_error;
        }
    }
  else
    graphic->logo = NULL;

#if DEBUG
  printf ("graphic_init: initing text\n");
  fflush (stdout);
#endif
  if (!text_init (graphic->text))
    {
      error_message = "unable to init the text";
      goto exit_on_error;
    }

#if DEBUG
  printf ("graphic_init: end\n");
  fflush (stdout);
#endif
  return 1;

exit_on_error:
  printf ("ERROR! %s\n", error_message);
#if DEBUG
  printf ("graphic_init: end\n");
  fflush (stdout);
#endif
  return 0;
}

/**
 * Function to free the memory used by graphic drawing functions.
 */
void
graphic_destroy (Graphic * graphic)     ///< Graphic struct.
{
#if DEBUG
  printf ("graphic_destroy: start\n");
  fflush (stdout);
#endif
  text_destroy (graphic->text);
  image_destroy (graphic->logo);
#if DEBUG
  printf ("graphic_destroy: end\n");
  fflush (stdout);
#endif
}

/**
 * Function to draw the fractal.
 */
void
graphic_render (Graphic * graphic)      ///< Graphic struct.
{
  // Rectangle matrix
  const Point3D square_vertices[4] = {
    {{0., 0., 0.}, {0., 0., 0.}},
    {{length, 0., 0.}, {0., 0., 0.}},
    {{length, width, 0.}, {0., 0., 0.}},
    {{0., width, 0.}, {0., 0., 0.}}
  };
  const GLushort square_indices[4] = { 0, 1, 2, 3 };
  const GLfloat black[4] = { 0., 0., 0., 1. };
  const char *str_version = "Fractal 3.4.15";
  float cp, sp, ct, st, w, h, sx, sy;
  GLuint vbo_square, ibo_square, vbo_points;

#if DEBUG
  printf ("graphic_render: start\n");
  fflush (stdout);
#endif

  // Drawing a white background
  glClearColor (1., 1., 1., 0.);
  glClear (GL_COLOR_BUFFER_BIT);

#if DEBUG
  printf ("graphic_render: ending if no fractal\n");
  fflush (stdout);
#endif

  // Ending if no fractal
  if (!medium)
    goto end_draw;

#if DEBUG
  printf ("graphic_render: checking the fractal type\n");
  fflush (stdout);
#endif

  // Checking if 3D or 2D fractal
  glUseProgram (graphic->program_3D);
  if (fractal_3D)
    {
      // Projection matrix
      sincosf (graphic->phi, &sp, &cp);
      sincosf (graphic->theta, &st, &ct);
      w = graphic->xmax - graphic->xmin;
      h = graphic->ymax - graphic->ymin;
      graphic->projection_matrix[0] = 2. * cp / w;
      graphic->projection_matrix[1] = 2. * ct * sp / h;
      graphic->projection_matrix[4] = -2. * sp / w;
      graphic->projection_matrix[5] = 2. * ct * cp / h;
      graphic->projection_matrix[9] = 2. * st / h;
      graphic->projection_matrix[12] = -1.;
      graphic->projection_matrix[13] = -1. - 2. * graphic->ymin / h;
      glUniformMatrix4fv (graphic->uniform_3D_matrix, 1, GL_FALSE,
                          graphic->projection_matrix);

      // Drawing a black rectangle
      glGenBuffers (1, &vbo_square);
      glBindBuffer (GL_ARRAY_BUFFER, vbo_square);
      glBufferData (GL_ARRAY_BUFFER, sizeof (square_vertices), square_vertices,
                    GL_DYNAMIC_DRAW);
      glGenBuffers (1, &ibo_square);
      glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, ibo_square);
      glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (square_indices),
                    square_indices, GL_DYNAMIC_DRAW);
      glBindBuffer (GL_ARRAY_BUFFER, vbo_square);
      glEnableVertexAttribArray (graphic->attribute_3D_position);
      glVertexAttribPointer (graphic->attribute_3D_position,
                             3, GL_FLOAT, GL_FALSE, sizeof (Point3D), NULL);
      glEnableVertexAttribArray (graphic->attribute_3D_color);
      glVertexAttribPointer (graphic->attribute_3D_color,
                             3,
                             GL_FLOAT,
                             GL_FALSE,
                             sizeof (Point3D),
                             (GLvoid *) offsetof (Point3D, c));
      glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, ibo_square);
      glDrawElements (GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0);
      glDeleteBuffers (1, &ibo_square);
      glDeleteBuffers (1, &vbo_square);
      glDisableVertexAttribArray (graphic->attribute_3D_color);
      glDisableVertexAttribArray (graphic->attribute_3D_position);
    }
  else
    {
      // Projection matrix
      graphic->projection_matrix[0] = 2. / width;
      graphic->projection_matrix[5] = 2. / height;
      graphic->projection_matrix[12] = graphic->projection_matrix[13] = -1.;
      graphic->projection_matrix[1] = graphic->projection_matrix[4]
        = graphic->projection_matrix[9] = 0.;
      glUniformMatrix4fv (graphic->uniform_3D_matrix, 1, GL_FALSE,
                          graphic->projection_matrix);
    }

#if DEBUG
  printf ("graphic_render: drawing the fractal points\n");
  fflush (stdout);
#endif

  // Drawing the fractal points
  glGenBuffers (1, &vbo_points);
  glBindBuffer (GL_ARRAY_BUFFER, vbo_points);
  glBufferData (GL_ARRAY_BUFFER, npoints * sizeof (Point3D), point,
                GL_DYNAMIC_DRAW);
  glEnableVertexAttribArray (graphic->attribute_3D_position);
  glVertexAttribPointer (graphic->attribute_3D_position,
                         3, GL_FLOAT, GL_FALSE, sizeof (Point3D), NULL);
  glEnableVertexAttribArray (graphic->attribute_3D_color);
  glVertexAttribPointer (graphic->attribute_3D_color,
                         3,
                         GL_FLOAT,
                         GL_FALSE,
                         sizeof (Point3D), (GLvoid *) offsetof (Point3D, c));
  glDrawArrays (GL_POINTS, 0, npoints);
  glDeleteBuffers (1, &vbo_points);
  glDisableVertexAttribArray (graphic->attribute_3D_color);
  glDisableVertexAttribArray (graphic->attribute_3D_position);

end_draw:

  // OpenGL properties
  glEnable (GL_BLEND);
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

#if DEBUG
  printf ("graphic_render: drawing the logo\n");
  fflush (stdout);
#endif

  // Drawing the logo
  image_draw (graphic->logo, 0, 0, window_width, window_height);

#if DEBUG
  printf ("graphic_render: displaying the program version\n");
  fflush (stdout);
#endif

  // Displaying the program version
  sx = 0.15 * 12. / window_width;
  sy = 0.15 * 12. / window_height;
  text_draw (graphic->text, (char *) str_version,
             0.99 - 7. * strlen (str_version) * sx, -0.99, sx, sy, black);

  // Disabling OpenGL properties
  glDisable (GL_BLEND);

#if DEBUG
  printf ("graphic_render: displaying the draw\n");
  fflush (stdout);
#endif

#if DEBUG
  printf ("graphic_render: end\n");
  fflush (stdout);
#endif
}

/**
 * Function to save the draw in a PNG file.
 */
void
graphic_save (char *file_name)  ///< File name.
{
  png_struct *png;
  png_info *info;
  png_byte **row_pointers;
  GLubyte *pixels;
  FILE *file;
  unsigned int i, row_bytes, pointers_bytes, pixels_bytes;

#if DEBUG
  printf ("graphic_save: start\n");
  fflush (stdout);
#endif

  // Creating the PNG header
  png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png)
    return;
  info = png_create_info_struct (png);
  if (!info)
    return;
  file = fopen (file_name, "wb");
  if (!file)
    return;
  if (setjmp (png_jmpbuf (png)))
    {
      printf ("Error png_init_io\n");
      exit (0);
    }
  png_init_io (png, file);
  if (setjmp (png_jmpbuf (png)))
    {
      printf ("Error png_set_IHDR\n");
      exit (0);
    }
  png_set_IHDR (png,
                info,
                window_width,
                window_height,
                8,
                PNG_COLOR_TYPE_RGBA,
                PNG_INTERLACE_NONE,
                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  if (setjmp (png_jmpbuf (png)))
    {
      printf ("Error png_write_info\n");
      exit (0);
    }
  png_write_info (png, info);

  // Getting the OpenGL pixels
  glViewport (0, 0, window_width, window_height);
  row_bytes = 4 * window_width;
  pixels_bytes = row_bytes * window_height;
  pixels = (GLubyte *) g_slice_alloc (pixels_bytes);
  glReadPixels (0, 0, window_width, window_height, GL_RGBA, GL_UNSIGNED_BYTE,
                pixels);

  // Saving the pixels in the PNG order
  pointers_bytes = window_height * sizeof (png_byte *);
  row_pointers = (png_byte **) g_slice_alloc (pointers_bytes);
  for (i = 0; i < window_height; ++i)
    {
      row_pointers[i] = (png_byte *) g_slice_alloc (row_bytes);
      memcpy (row_pointers[i], pixels + (window_height - 1 - i) * row_bytes,
              row_bytes);
    }
  if (setjmp (png_jmpbuf (png)))
    {
      printf ("Error png_write_image\n");
      exit (0);
    }
  png_write_image (png, row_pointers);

  // Freeing memory
  for (i = 0; i < window_height; ++i)
    g_slice_free1 (row_bytes, row_pointers[i]);
  g_slice_free1 (pointers_bytes, row_pointers);
  g_slice_free1 (pixels_bytes, pixels);

  // Saving the file
  if (setjmp (png_jmpbuf (png)))
    {
      printf ("Error png_write_end\n");
      exit (0);
    }
  png_write_end (png, NULL);
  fclose (file);

  // Freeing memory
  png_destroy_write_struct (&png, &info);

#if DEBUG
  printf ("graphic_save: end\n");
  fflush (stdout);
#endif
}