#include <gsl/gsl_math.h>
#include "gsl_cblas.h"
#include "cblas.h"

void
cblas_zgemv (const enum CBLAS_ORDER order, const enum CBLAS_TRANSPOSE TransA,
	     const int M, const int N, const void *alpha, const void *A,
	     const int lda, const void *X, const int incX, const void *beta,
	     void *Y, const int incY)
{
#define BASE double
#include "source_gemv_c.h"
#undef BASE
}


#ifndef _FastFiz_h
#define _FastFiz_h

#ifdef SWIG
%include exception.i
%include "std_string.i"
%{
#include "FastFiz.h"
%}
#endif /* SWIG */

#include <gsl/gsl_rng.h>
#include <iosfwd>
#include <list>
#include <sstream>
#include <string>
#include <vector>

// TODO: add a setprecision for double print out

/**
 * The namespace in which all of the physics and rules components for FastFiz
 * reside.
 */
namespace Pool {

class BadShotException;
struct ShotParams;
struct Point;
struct Vector;
class Ball;
class TableState;
class Table;
class Event;
class Shot;
class Utils;
#ifndef SWIG

/**
 * The exception thrown when a Shot cannot be completed.
 * It can be thrown when TableState::executeShot() or
 * TableState::getFirstBallHit() is called.
 * The Type cannot be changed after construction.
 */
class BadShotException : public std::exception {
public:
  enum Type {
    OK,                 /**< The Shot was okay. */
    MISSED_BALL,        /**< The Shot missed the CUE ball. */
    INVALID_CUE_PARAMS, /**< The ShotParams for the Shot in the current
                           TableState were out of range or not physically
                           possible. */
    POOLFIZ_ERROR,      /**< FastFiz encountered some sort of error. */
    UNKNOWN_ERROR       /**< An unknown error. */
  };

  /**
   * Constructs a BadShotException initialized with the given Type.
   * There is no default constructor.
   */
  BadShotException(Type type) : _type(type) {}

  /**
   * Returns the Type of the BadShotException.
   */
  Type getType() const { return _type; }

  /**
   * Returns the Type of the BadShotException as a string.
   */
  std::string getTypeString() const;

  /**
   * Returns a const char* pointing to a c string about what type of Exception
   * this is.
   */
  virtual const char *what() const throw() { return "Bad Shot Exception"; }

private:
  const Type _type;
};
#endif /* SWIG */

/**
 * A struct of the parameters for a CUE_STRIKE.  It is passed to
 * TableState::executeShot() and can be retrieved from CueStrikeEvent.
 * @see operator<<(ostream &out, const ShotParams &rhs) Writes human-readable
 * output for ShotParams objects to the output stream.
 */
struct ShotParams {
  double a; /**< The x-coordinate of the cue stick (right/left english) on the
               CUE ball in mm. */
  double b; /**< The y-coordinate of the cue stick (top/bottom english) on the
               CUE ball in mm. */
  double theta; /**< The elevation of the cue stick in degrees. */
  double phi;   /**< The azumith angle (heading) of the cue stick in degrees. */
  double
      v; /**< The velocity of the cue stick before impact in m/s (max is 4.5
            m/s). */

  /**
   * Constructs a ShotParams object with all the fields initialized to 0.0.
   */
  ShotParams() : a(0.0), b(0.0), theta(0.0), phi(0.0), v(0.0) {}

  /**
   * Constructs a ShotParams object with all the fields initialized to the given
   * values.
   * @param _a     The x-coordinate of the cue stick (right/left english) on the
   * CUE ball in mm.
   * @param _b     The y-coordinate of the cue stick (top/bottom english) on the
   * CUE ball in mm.
   * @param _theta The elevation of the cue stick in degrees.
   * @param _phi   The azumith angle (heading) of the cue stick in degrees.
   * @param _v     The velocity of the cue stick before impact in m/s (max is
   * 4.5 m/s).
   */
  ShotParams(double _a, double _b, double _theta, double _phi, double _v)
      : a(_a), b(_b), theta(_theta), phi(_phi), v(_v) {}

  /**
   * Copy constructor.
   */
  ShotParams(const ShotParams &rhs)
      : a(rhs.a), b(rhs.b), theta(rhs.theta), phi(rhs.phi), v(rhs.v) {}
};

#ifndef SWIG
/**
 * Writes human-readable output for the ShotParams object to the output stream.
 */
std::ostream &operator<<(std::ostream &out, const ShotParams &rhs);
#endif /* SWIG */

/**
 * A two-dimensional Point class. It has methods for a few simple point
 * operations.
 * @see operator<<(ostream &out, const Point &rhs) Writes human-readable output
 * for Point objects to the output stream.
 */
struct Point {
  double x; /**< The x-coordinate of the Point in meters. */
  double y; /**< The y-coordinate of the Point in meters. */

  /**
   * Constructs a Point object with x and y initialized to 0.0.
   */
  Point() : x(0.0), y(0.0) {}

  /**
   * Constructs a Point object with x and y initialized to the given values.
   */
  Point(double xx, double yy) : x(xx), y(yy) {}

  /**
   * Copy constructor.
   */
  Point(const Point &rhs) : x(rhs.x), y(rhs.y) {}

#ifndef SWIG
  /**
   * Calculates the rotation of a Point object about the origin.  The angle of
   * rotation is counterclockwise.
   * @param cos_phi The cos of the angle to be rotated by.
   * @param sin_phi The sin of the anlge to be rotated by.
   * @return A new Point object that is a copy of this Point object rotated
   * about the origin by the angle
   *         represented by the cos and sin values.
   */
  Point rotate(double cos_phi, double sin_phi) const;

  /**
   * Creates a Vector object representation of this Point object.
   * @return A new Vector object that is a copy of this Point object with the z
   * field initialized to 0.0.
   */
  Vector to_v() const;

  /**
   * Calculates the sum of two Points.
   * @param p2 The other Point object to be added.
   * @return A new Point object that has the respective x and y components of
   * the other Point object
   *         added to this Point object's components.
   */
  Point operator+(const Point &p2) const;

  /**
   * Returns a new Point object that has the respective x and y components of
   * the other Point object
   * subtracted from this Point object's components.
   */
  Point operator-(const Point &p2) const;

  /**
   * Writes a machine-readable string representation of this Point object (a
   * sequence of space-separated
   * doubles followed by a trailing space) to the stream provided.
   * It can later be interpreted by fromStream() of fromString().
   */
  void toStream(std::ostream &out) const;

  /**
   * Reads a machine-readable string representation of a Point (a sequence of
   * space-separated doubles)
   * written by toStream() or toString() from the stream provided and assigns
   * the values to this Point object.
   */
  void fromStream(std::istream &in);

#endif /* ! SWIG */

  /**
   * Returns a string object that is a machine-readable string representation of
   * this Point object
   * (a sequence of space-separated doubles followed by a trailing space).
   * It can later be interpreted by fromString() or fromStream().
   */
  std::string toString() const;

  /**
   * Takes a machine-readable string representation of a Point (a sequence of
   * space-separated doubles)
   * created by toString() or toStream() and assigns the values to this Point
   * object.
   */
  void fromString(const std::string &s);
};

#ifndef SWIG
/**
 * Writes human-readable output for the Point object to the output stream.
 */
std::ostream &operator<<(std::ostream &out, const Point &rhs);

#endif /* !SWIG */

/**
 * A three-dimensional Vector class. It has methods for various vector
 * operations.
 * @see operator<<(ostream &out, const Vector &rhs) Writes human-readable output
 * for Vector objects to the output stream.
 */
struct Vector {
  double x; /**< The x-coordinate of the Vector in meters. */
  double y; /**< The y-coordinate of the Vector in meters. */
  double z; /**< The z-coordinate of the Vector in meters. */

  /**
   * Constructs a Vector object with x, y and z initialized to 0.0.
   */
  Vector() : x(0.0), y(0.0), z(0.0) {}

  /**
   * Constructs a Point object with x, y and z initialized to the given values.
   */
  Vector(double xx, double yy, double zz) : x(xx), y(yy), z(zz) {}

  /**
   * Copy constructor.
   */
  Vector(const Vector &rhs) : x(rhs.x), y(rhs.y), z(rhs.z) {}

#ifndef SWIG
  /**
   * Returns a new Vector object that has the respective x, y, and z components
   * of this Vector object
   * multiplied with the coefficient provided.
   */
  Vector operator*(double d) const;

  /**
   * Multiplies the x,y,z coordinates of the vector by the coefficient provided.
   */
  Vector &operator*=(double d);

  /**
   * Returns a new Vector object that has the respective x, y, and z components
   * of the other Vector object
   * subtracted from this Vector object's components.
   */
  Vector operator-(const Vector &fizV) const;

  /**
   * Returns a new Vector object that has the respective x, y, and z components
   * of the other Vector object
   * added to this Vector object's components.
   */
  Vector operator+(const Vector &fizV) const;

  /**
   * Returns a new Vector object that is a copy of this Vector object rotated
   * about the origin.
   * The parameter is in radians.  The angle is counterclockwise.
   */
  Vector rotateRad(double rad) const; // takes radians
  /**
   * Returns a new Vector object that is a copy of this Vector object rotated
   * about the origin.
   * The parameter is in degrees.  The angle is counterclockwise.
   */
  Vector rotateDeg(double phi) const; // takes degrees
  /**
   * Returns a new Vector object that is a copy of this Vector object rotated
   * about the origin.
   * The parameters are the cos and sin of the angle to be rotated by.  The
   * angle is counterclockwise.
   */
  Vector rotate(double cos_phi, double sin_phi) const;
  /**
   * Returns dot-product of two vectors.
   */
  double dot(const Vector &v2) const;
  /**
   * Returns cross-product of two vectors.
   */
  Vector cross(const Vector &v2) const;
  /**
   * Returns the length (magnitude) of a vector.
   */
  double mag() const;
  /**
   * Returns the vector divided by its magnitude.
   */
  Vector norm() const;
  /**
   * Returns a point with same x,y as the vector.
   */
  Point to_p() const;

  void toStream(std::ostream &out) const;
  void fromStream(std::istream &in);
#endif /* ! SWIG */
  std::string toString() const;
  void fromString(const std::string &s);
};
#ifndef SWIG
std::ostream &operator<<(std::ostream &out,
                    const Vector &rhs); // doesn't need to be friend
#endif                                  /* ! SWIG */

#ifndef SWIG
/** General utility functions */
class Utils {
public:
  static constexpr double EPSILON = 1.0E-11; /**< double comparison threshold */
  static constexpr double VELOCITY_EPSILON =
      1E-10; /**< threshold velocity for balls to be considered stationary. */
  // Angle ranges can START_ZERO [0,2pi) or START_NEG_HALF_CIRCLE [-pi,pi)
  // This can apply to degrees or radians
  enum ANGLE_RANGE { START_ZERO, START_NEG_HALF_CIRCLE };
  enum ANGLE_UNIT { DEGREES, RADIANS };

  /** direction in the plane from p1 to p2 */
  static double angle(Point p1, Point p2, ANGLE_RANGE range, ANGLE_UNIT unit);
  /** converts radians to degrees */
  static double toDegrees(double angleRad);
  /** converts an angle in radians to be on the specified range, either [0,2*pi)
   * or [-pi,pi) */
  static double normalizeRadianAngleRange(double angle, ANGLE_RANGE range);

  /** A random number generator instance */
  static gsl_rng *rng();

  /** Equality test for doubles. */
  static bool fequal(double a, double b);
  /** Less than test for doubles. */
  static bool fless(double a, double b);
  /** Greater than test for doubles. */
  static bool fgreater(double a, double b);
  /** Greater than or equal test for doubles. */
  static bool fgreaterequal(double a, double b);
  /** Less than or equal test for doubles. */
  static bool flessequal(double a, double b);
  /** Check if velocity absolute value should be considered zero. */
  static bool vzero(double a);

private:
  static gsl_rng *_rng;
};
#endif /* ! SWIG */

/** This class represents the state and position of a single pool ball.
 *  It is mostly used internally for execution of the physics, and as part of a
 * TableState object.
 */
class Ball {
public:
#ifndef SWIG
  static constexpr double MU_BALL_BALL =
      0.01; /**< coefficient of ball-ball friction */
  static constexpr double MU_CUETIP_BALL =
      0.7; /**< coefficient of cue tip-ball friction */
  static constexpr double BALL_COEFF_REST_POS =
      2.0; /**< coefficient of restitution for balls */
  static constexpr double BALL_COEFF_REST_NEG =
      0.0; /**< coefficient of restitution for balls */
  static constexpr double BALL_MASS = 163.01;     /**< 5.57 oz. ball mass [g] */
  static constexpr double BALL_RADIUS = 0.028575; /**< 2.25" ball radius [m] */
#endif                                            /* SWIG */

  /** The present physical state of the ball. */
  enum State {
    NOTINPLAY,  /**< not on the table */
    STATIONARY, /**< in play but not moving */
    SPINNING,   /**< not moving translationally, but spinning in place about the
                   vertical axis */
    SLIDING, /**< sliding across the surface of the table, not necessarily in a
                straight trajectory */
    ROLLING, /**< rolling across the surface of the table, necessarily in a
                straight trajectory */
    POCKETED_SW,      /**< pocketed in the SW pocket */
    POCKETED_W,       /**< pocketed in the W pocket */
    POCKETED_NW,      /**< pocketed in the NW pocket */
    POCKETED_NE,      /**< pocketed in the NE pocket */
    POCKETED_E,       /**< pocketed in the E pocket */
    POCKETED_SE,      /**< pocketed in the SE pocket */
    SLIDING_SPINNING, /**< Transition between SLIDING and SPINNING */
    ROLLING_SPINNING, /**< Transition between ROLLING and SPINNING */
    UNKNOWN_STATE     /**< in an unknown state */
  };

  /** The type (number) of the ball. */
  enum Type {
    CUE,
    ONE,
    TWO,
    THREE,
    FOUR,
    FIVE,
    SIX,
    SEVEN,
    EIGHT,
    NINE,
    TEN,
    ELEVEN,
    TWELVE,
    THIRTEEN,
    FOURTEEN,
    FIFTEEN,
    UNKNOWN_ID
  };

  /** Create a new ball */
  Ball()
      : radius(BALL_RADIUS), r(), state(UNKNOWN_STATE), type(UNKNOWN_ID), v(),
        w() {}

  /** Create a new ball with specified number */
  Ball(Type _type)
      : radius(BALL_RADIUS), r(), state(UNKNOWN_STATE), type(_type), v(), w() {}
#ifndef SWIG
  /** Create a new ball with specified number and state */
  Ball(Type _type, State _state)
      : radius(BALL_RADIUS), r(), state(_state), type(_type), v(), w() {}
  /** Create a new ball with specified number, state, and position */
  Ball(Type _type, State _state, Point _r)
      : radius(BALL_RADIUS), r(_r), state(_state), type(_type), v(), w() {}
  /** Create a new ball with specified number, state, and position */
  Ball(Type _type, State _state, double x, double y)
      : radius(BALL_RADIUS), r(x, y), state(_state), type(_type), v(), w() {}
#endif /* ! SWIG */

  /** Copy constructor */
  Ball(const Ball &rhs)
      : radius(rhs.radius), r(rhs.r), state(rhs.state), type(rhs.type),
        v(rhs.v), w(rhs.w) {}
#ifndef SWIG
  /** Assignment operator */
  const Ball &operator=(const Ball &rhs);
#endif /* ! SWIG */

  /** Returns the radius of the ball in meters. */
  double getRadius() const { return radius; }
  /** Returns the ID (number) of the ball */
  Type getID() const { return type; }
  /** Returns the name of the ball (CUE, ONE, etc.) as a string */
  std::string getIDString() const;
  /** Returns the physical state of the ball */
  State getState() const { return state; }
  /** Returns the physical state of the ball as a string */
  std::string getStateString() const;
  /** Returns the x,y position of the ball */
  const Point &getPos() const { return r; }
  /** Returns the x,y,z velocity of the ball */
  const Vector &getVelocity() const { return v; }
  /** Returns the x,y,z spin of the ball */
  const Vector &getSpin() const { return w; }

  /** Set the number of the ball */
  void setID(Type t) { type = t; }
  /** Set the position of the ball */
  void setPos(Point pos) { r = pos; }
  /** Set the velocity of the ball */
  void setVelocity(Vector vel) { v = vel; }
  /** Set the spin of the ball */
  void setSpin(Vector spin) { w = spin; }
  /** Set the physical state of the ball */
  void setState(State s) { state = s; }
  /** Returns true iff the ball is on the table. */
  bool isInPlay() const {
    return (state == STATIONARY || state == SPINNING || state == SLIDING ||
            state == ROLLING);
  }
  /** Returns true iff the ball is in a pocket. */
  bool isPocketed() const {
    return (state == POCKETED_SW || state == POCKETED_W ||
            state == POCKETED_NW || state == POCKETED_NE ||
            state == POCKETED_E || state == POCKETED_SE);
  }
#ifndef SWIG
  /** Returns true if the ball occupies the same space as the other ball */
  bool overlaps(const Ball &other, double epsilon = Utils::EPSILON) const;

  void moveAway(Ball &other, double epsilon);

  /** Returns the distance between the centers of this ball and the other ball.
   * Note that a positive distance does not indicate no overlap.
   * No overlap is ensured if the distance is greater than the sum of the
   * radiuses of the balls.
   */
  double dist(const Ball &other) const;
  /** Add small gaussian noise to ball's position based on dither parameter
   * passed.
   * This method is used for racking and spotting noise, and has nothing to do
   * with shot execution noise.
   */
  void addNoise(double dither);
#endif /* ! SWIG */
       /** Update balls physical state based on position, velocity, and spin.
        *  Used internally for physics calculations.
        */
  void updateState(bool VERBOSE = false);

#ifndef SWIG
  /** Print a machine-readable representation of the ball's type, radius and
   * position.
   * Only writes location information, not velocity and spin.
   */
  void toStream(std::ostream &out) const;
  /** Read a machine-readable representation of the ball's type, radius and
   * position.
   * Should be used on data written by toStream()/toString().
   */
  void fromStream(std::istream &in);
#endif /* ! SWIG */
  /** Returns a string including a machine-readable representation of the ball's
   * type, radius and position.
   * Only outputs location information, not velocity and spin.
   */
  std::string toString() const;
  /** Read a machine-readable representation of the ball's type, radius and
   * position from string.
   * Should be used on data created by toString()/toStream().
   */
  void fromString(const std::string &s);
#ifndef SWIG

private:
  double radius;
  Point r;
  State state;
  Type type;
  Vector v;
  Vector w;
#endif /* ! SWIG */
};

#ifndef SWIG
std::ostream &operator<<(std::ostream &out,
                    const Ball &rhs); // doesn't need to be a friend
#endif                                /* !SWIG */

/** Class representing physical properties of a pool table. This does not
 * include the position of the balls.
 * In general, this object doesn't need to be instansiated more than once.
 * This class also provides some static utility functions and constants related
 * to the pool table.
 */
class Table {
public:
  /* Physics constants */
  static constexpr double g = 9.81; /**< Gravitational constant.*/
  static constexpr double MU_SLIDING =
      0.2; /**< coefficient of sliding friction */
  static constexpr double MU_ROLLING =
      0.015; /**< coefficient of rolling friction */
  static constexpr double MU_SPINNING =
      0.044; /**< coefficient of spinning friction */

  /* Default table parameters */
  static constexpr double TABLE_LENGTH = 2.236; /**< table length [m] */
  static constexpr double TABLE_WIDTH = 1.116;  /**< table width [m] */
  static constexpr double CORNER_POCKET_WIDTH =
      0.11; /**< corner pocket width [m] */
  static constexpr double SIDE_POCKET_WIDTH =
      0.12;                                       /**< side pocket width [m] */
  static constexpr double RAIL_HEIGHT = 0.040005; /**< rail height [m] */
  static constexpr double CUE_LENGTH = 1.45;      /**< cue length [m] */
  static constexpr double RAIL_VEL_DAMPING_X =
      0.6; /**< damping factor for velocity component parallel to rail */
  static constexpr double RAIL_VEL_DAMPING_Y =
      0.9; /**< damping factor for velocity component perpendicular to rail */
  static constexpr double RAIL_SPIN_DAMPING =
      0.1; /**< damping factor for angular velocity component */
  static constexpr double RAIL_VEL_ANGLE_ADJ =
      0.0; /**< angle adjustment factor for velocity vector */
  static constexpr double RAIL_ZSPIN_ANGLE_ADJ =
      0.0; /**< angle adjustment factor for vertical component of angular
              velocity vector */

  // used in CueStrikeEvent::doHandle
  static constexpr double CUE_MASS = 600.0;
  static constexpr double I =
      0.4 * 160.0 * 0.028575 * 0.028575 *
      0.995473; /**< moment of inertia; to match poolfiz */

  /** A rail or a pocket. */
  enum BoundaryId {
    SW_POCKET,
    SW_RAIL,
    W_POCKET,
    NW_RAIL,
    NW_POCKET,
    N_RAIL,
    NE_POCKET,
    NE_RAIL,
    E_POCKET,
    SE_RAIL,
    SE_POCKET,
    S_RAIL,
    UNKNOWN_BOUNDARY
  };

  enum Pocket { SW, W, NW, NE, E, SE, UNKNOWN_POCKET };

  /** Constructs a table with the default parameters */
  Table()
      : _muS(MU_SLIDING), _muR(MU_ROLLING), _muSp(MU_SPINNING),
        _railHeight(RAIL_HEIGHT), _cueLength(CUE_LENGTH),
        _railVelDampingX(RAIL_VEL_DAMPING_X),
        _railVelDampingY(RAIL_VEL_DAMPING_Y),
        _railSpinDamping(RAIL_SPIN_DAMPING),
        _railZSpinAngleAdj(RAIL_ZSPIN_ANGLE_ADJ),
        _railVelAngleAdj(RAIL_VEL_ANGLE_ADJ) {
    calculateTableDimensions(TABLE_LENGTH, TABLE_WIDTH, CORNER_POCKET_WIDTH,
                             SIDE_POCKET_WIDTH);
  }

  /** Constructs a table with the given parameters and automatically sets the
   *pockets.
   *	@param length  the length of the table in metres
   *	@param width the width of the table in metres
   *	@param cornerPocketWidth the width of corner pockets (horn to horn) in
   *metres
   *	@param sidePocketWidth the width of the side pockets (horn to horn) in
   *metres
   *	@param muS the coefficient of sliding friction (dimensionless)
   *	@param muR the coefficient of rolling friction (dimensionless)
   *	@param muSp the coefficient of spinning friction (dimensionless)
   *	@param railHeight the height of the top of the rail above the table in
   *metres
   *	@param cueLength the length of the cue in metres
   *	@param railVelDampingX velocity damping factor of the banks (X)
   *  @param railVelDampingY velocity damping factor of the banks (Y)
   *	@param railSpinDamping spin damping factor of the banks
   *	@param railZSpinAngleAdj z-spin angle of deflection factor of the banks
   *	@param railVelAngleAdj velocity deflection factor of the banks */
  Table(double length, double width, double cornerPocketWidth,
        double sidePocketWidth, double muS = MU_SLIDING,
        double muR = MU_ROLLING, double muSp = MU_SPINNING,
        double railHeight = RAIL_HEIGHT, double cueLength = CUE_LENGTH,
        double railVelDampingX = RAIL_VEL_DAMPING_X,
        double railVelDampingY = RAIL_VEL_DAMPING_Y,
        double railSpinDamping = RAIL_SPIN_DAMPING,
        double railZSpinAngleAdj = RAIL_ZSPIN_ANGLE_ADJ,
        double railVelAngleAdj = RAIL_VEL_ANGLE_ADJ);

  /** Copy constructor. */
  Table(const Table &rhs);

#ifndef SWIG
  /** Assignment operator */
  const Table &operator=(const Table &rhs);
#endif /* SWIG */

  /* Convenience methods for the table parameters */

  /** Returns the length of the table (in metres). */
  double getLength() const { return _length; }

  /** Returns the width of the table (in metres). */
  double getWidth() const { return _width; }

  /** Returns the y-coordinate of the headstring of the table (in metres) */
  double getHeadString() const { return _headString; }

  /** Returns the x-y coordinate of the footspot of the table (in metres) */
  const Point &getFootSpot() const { return _footSpot; }

  /** Sets the length of the cue stick.
   *	@param length the length of the cue in metres. */
  void setCueLength(double length) { _cueLength = length; }

  /** Returns the length of the cue stick. */
  double getCueLength() const { return _cueLength; }

  /** Sets the height of the rails around the table.
   *	@param height the height of the rails in metres. */
  void setRailHeight(double height) { _railHeight = height; }

  /** Returns the height of the rails around the table. */
  double getRailHeight() const { return _railHeight; }

  /** Sets the coefficient of sliding friction.
   *	@param mu the coefficient of sliding friction (between 0 and 1). */
  void setMuSliding(double mu) { _muS = mu; }

  /** Returns the coefficient of sliding friction. */
  double getMuSliding() const { return _muS; }

  /** Sets the coefficient of rolling friction.
   *	@param mu the coefficient of rolling friction (between 0 and 1). */
  void setMuRolling(double mu) { _muR = mu; }

  /** Returns the coefficient of rolling friction. */
  double getMuRolling() const { return _muR; }

  /** Sets the coefficient of spinning friction.
   *	@param mu the coefficient of spinning friction (between 0 and 1). */
  void setMuSpinning(double mu) { _muSp = mu; }

  /** Returns the coefficient of spinning friction. */
  double getMuSpinning() const { return _muSp; }

  /** Returns the aiming point of the given pocket (in metres). */
  const Point &getPocketCenter(Pocket pocket) const;

  /** Returns the right corner coordinates of the given pocket (in metres),
   *looking
   *	at the pocket from the center of the table. */
  const Point &getPocketRight(Pocket pocket) const;

  /** Returns the left corner coordinates of the given pocket (in metres),
   *looking
   *	at the pocket from the center of the table. */
  const Point &getPocketLeft(Pocket pocket) const;

  /** Contains a single default table object whose reference is returned when
   * called */
  static const Table &defaultTable() {
    static const Table t = Table();
    return t;
  }

  /** Returns the pocketed ball state corresponding to the given pocket (by
   * Pocket) */
  static Ball::State stateFromPocket(Pocket pocket);
  /** Returns the same pocket in Pocket form rather than BoundaryId form */
  static Pocket pocketFromBndId(BoundaryId bnd);
  /** Returns the same pocket in BoundaryId form rather than Pocket form */
  static BoundaryId bndIdFromPocket(Pocket pocket);
  /** returns a string of the boundary name */
  static std::string boundaryName(BoundaryId boundary);
  /** returns a string of the pocket name */
  static std::string pocketName(Pocket pocket);
#ifndef SWIG

private:
  double _muS;
  double _muR;
  double _muSp;
  double _railHeight;
  double _cueLength;
  double _railVelDampingX;
  double _railVelDampingY;
  double _railSpinDamping;
  double _railZSpinAngleAdj;
  double _railVelAngleAdj;

  double _length;
  double _width;
  double _headString;
  Point _footSpot;
  Point _SWpocketLeft;
  Point _SWpocketRight;
  Point _SWpocketCenter;
  Point _WpocketLeft;
  Point _WpocketRight;
  Point _WpocketCenter;
  Point _NWpocketLeft;
  Point _NWpocketRight;
  Point _NWpocketCenter;
  Point _NEpocketLeft;
  Point _NEpocketRight;
  Point _NEpocketCenter;
  Point _EpocketLeft;
  Point _EpocketRight;
  Point _EpocketCenter;
  Point _SEpocketLeft;
  Point _SEpocketRight;
  Point _SEpocketCenter;

  void calculateTableDimensions(double length, double width,
                                double cornerPocketWidth,
                                double sidePocketWidth);
#endif /* ! SWIG */
};

/** Base class of the Event heirarchy. Indicates a notable event in the
 * execution of a shot.
 *
 * Subclasses of this class indicate specific events.
 */
class Event {
#ifndef SWIG
  friend std::ostream &operator<<(std::ostream &out, const Event &rhs);
#endif /* ! SWIG */
public:
  /** Indicates the type of event.*/
  enum Type {
    NO_EVENT,       /**< Nothing happened (only used internally) */
    STATE_CHANGE,   /**< A ball transitioned to a different motion state */
    BALL_COLLISION, /**< two balls collided */
    RAIL_COLLISION, /**< a ball collided with a rail */
    POCKETED,       /**< a ball was pocketed */
    CUE_STRIKE, /**< the cue ball was struck by the cue stick successfully */
    MISCUE,     /**< the cue ball was struck by the cue stick unsuccessfully */
    UNKNOWN_EVENT /**< an unknown event */
  };

  /** Create a new base event.
   * \param time Simulation time event took place.
   * \param b id of the ball affected by the event.
   */
  Event(double time, Ball::Type b) : _time(time), _ball1(b), _ball1Data(NULL) {}

  /** Returns the event's simulation time index */
  double getTime() const { return _time; }

  /** Returns the id of first (possibly only) ball involved in the event. */
  Ball::Type getBall1() const { return _ball1; }
  /** Returns the physical information (location, velocity,spin) of the first
   * (possibly only) ball involved in the event.
   * May cause a null pointer exception if the information is not available (if
   * event was not yet handled).
   */
  Ball &getBall1Data() { return *_ball1Data; }

  /** Sorts Events by time */
  bool operator<(const Event &other) const;
  /** Event comparison function, calls operator< */
  static bool eventCmp(const Event *event1, const Event *event2);

  /** Returns a human-readble string representation of the event. */
  std::string toString() const;

  /** Returns the type of the event */
  virtual Type getType() const { return UNKNOWN_EVENT; }
  /** Returns the type of the event as a string */
  virtual std::string getTypeString() const { return "Unknown Event"; }
  /** Returns the id of the second ball involved in the event, if applicable */
  virtual Ball::Type getBall2() const { return Ball::UNKNOWN_ID; }
  /** Returns the physical information (location, velocity,spin) of the second
   * ball involved in the event.
   * If no second ball is involved, will return the first ball information.
   * May cause a null pointer exception if the information is not available (if
   * event was not yet handled).
   */
  virtual Ball &getBall2Data() { return *_ball1Data; }
  /** Returns true if this event and the other event affect a shared ball. */
  virtual bool relatedTo(const Event &other) const;
  /** Returns true if this event affects specified ball. */
  virtual bool involvesBall(Ball::Type b) const;
  /** Destructor. */
  virtual ~Event() { delete _ball1Data; }

  /** Used within physics code to apply event to a table state, modifying ball
   * states, positions, and properties
   * Also updates ball information within event.
   */
  void handle(TableState &ts, bool VERBOSE = false) {
    doHandle(ts, VERBOSE);
    copyBalls(ts);
  }

protected:
  double _time;
  Ball::Type _ball1;
  Ball *_ball1Data;

  virtual void doHandle(TableState &ts, bool VERBOSE) const = 0;
  virtual void copyBalls(TableState &ts);
#ifndef SWIG
  virtual std::ostream &dump(std::ostream &out) const;

private:
  // copy and assignment
  Event(const Event &rhs); //: _time(rhs._time), _ball1(rhs._ball1) {}
  const Event &operator=(const Event &rhs); //{if (this != &rhs)
                                            //{_time=rhs._time;
                                            //_ball1=rhs._ball1;}; return
                                            //*this;}
#endif                                      /* ! SWIG */
};

/** An event invloving a physical transition of state, e.g between SLIDING and
 * ROLLING.
 * In general these events are important for graphical simulation of the shot,
 * and for trajectory analysis.
 */
class StateChangeEvent : public Event {
public:
  StateChangeEvent(double time, Ball::Type b) : Event(time, b) {}

  virtual Type getType() const { return STATE_CHANGE; }
  virtual std::string getTypeString() const { return "State Change"; }

protected:
  virtual void doHandle(TableState &ts, bool VERBOSE) const;
#ifndef SWIG
private:
  // copy and assignment
  StateChangeEvent(const StateChangeEvent &rhs); // : Event(rhs) {}
  StateChangeEvent &
  operator=(const StateChangeEvent &
                rhs); //{if (this != &rhs) Event::operator=(rhs); return *this;}
#endif                /* ! SWIG */
};

/** An event involving two balls colliding.
 * This is the only event where Ball2 is defined.
 */
class BallCollisionEvent : public Event {
public:
  BallCollisionEvent(double time, Ball::Type b1, Ball::Type b2)
      : Event(time, b1), _ball2(b2), _ball2Data(NULL) {}

  virtual Type getType() const { return BALL_COLLISION; }
  virtual std::string getTypeString() const { return "Ball Collision"; }
  virtual bool relatedTo(const Event &other) const;
  virtual bool involvesBall(Ball::Type b) const;
  virtual ~BallCollisionEvent() { delete _ball2Data; }

  virtual Ball::Type getBall2() const { return _ball2; }
  virtual Ball &getBall2Data() { return *_ball2Data; }

protected:
  Ball::Type _ball2;
  Ball *_ball2Data;

  virtual void copyBalls(TableState &ts);
  virtual void doHandle(TableState &ts, bool VERBOSE) const;
#ifndef SWIG
  virtual std::ostream &dump(std::ostream &out) const;

private:
  // copy and assignment
  BallCollisionEvent(
      const BallCollisionEvent &rhs); //: Event(rhs), _ball2(rhs._ball2) {}
  BallCollisionEvent &operator=(const BallCollisionEvent &rhs);
#endif /* ! SWIG */
};

/** An event involving a ball colliding with a rail. */
class RailCollisionEvent : public Event {
public:
  RailCollisionEvent(double time, Ball::Type b, Table::BoundaryId rail)
      : Event(time, b), _rail(rail) {}

  virtual Type getType() const { return RAIL_COLLISION; }
  virtual std::string getTypeString() const { return "Rail Collision"; }

  /** Returns the ID of the rail collided with. */
  Table::BoundaryId getRail() const { return _rail; }

protected:
  Table::BoundaryId _rail;

  virtual void doHandle(TableState &ts, bool VERBOSE) const;
#ifndef SWIG
  virtual std::ostream &dump(std::ostream &out) const;

private:
  // copy and assignment
  RailCollisionEvent(
      const RailCollisionEvent &rhs); //: Event(rhs), _rail(rhs._rail) {}
  RailCollisionEvent &operator=(const RailCollisionEvent &rhs);
#endif /* ! SWIG */
};

/** An event involving a ball entering a pocket. */
class PocketedEvent : public Event {
public:
  PocketedEvent(double time, Ball::Type b, Table::Pocket pocket)
      : Event(time, b), _pocket(pocket) {}

  virtual Type getType() const { return POCKETED; }
  virtual std::string getTypeString() const { return "Ball Pocketed"; }

  /** Returns the ID of the pocket. */
  Table::Pocket getPocket() const { return _pocket; }

protected:
  Table::Pocket _pocket;

  virtual void doHandle(TableState &ts, bool VERBOSE) const;
#ifndef SWIG
  virtual std::ostream &dump(std::ostream &out) const;

private:
  // copy and assignment
  PocketedEvent(
      const PocketedEvent &rhs); //: Event(rhs), _pocket(rhs._pocket) {}
  PocketedEvent &operator=(const PocketedEvent &rhs);
#endif /* ! SWIG */
};

/** The initial event in any shot -- cue ball struck by the cue stick. */
class CueStrikeEvent : public Event {
public:
  // Default constructor
  /** Constructor with shot parameters, assumes zero time */
  CueStrikeEvent(const ShotParams &params)
      : Event(0.0, Ball::CUE), _params(params) {}
  /** Constructor with shot parameters, and time */
  CueStrikeEvent(double time, const ShotParams &params)
      : Event(time, Ball::CUE), _params(params) {}
  /** Constructor with shot parameters, ball, and time */
  CueStrikeEvent(double time, Ball::Type &b, const ShotParams &params)
      : Event(time, b), _params(params) {}

  virtual Type getType() const { return CUE_STRIKE; }
  virtual std::string getTypeString() const { return "Cue Strike"; }

  /** Return shot parameters */
  const ShotParams &getParams() const { return _params; }

protected:
#ifndef SWIG
  ShotParams _params;
#endif /* SWIG */
  virtual void doHandle(TableState &ts, bool VERBOSE) const;
#ifndef SWIG
  virtual std::ostream &dump(std::ostream &out) const;

private:
  // copy and assignment
  CueStrikeEvent(
      const CueStrikeEvent &rhs); //: Event(rhs), _params(rhs._params) {}
  CueStrikeEvent &operator=(const CueStrikeEvent &rhs);
#endif /* ! SWIG */
};

StateChangeEvent& eventToStateChangeEvent(Event &event);

BallCollisionEvent& eventToBallCollisionEvent(Event &event);

RailCollisionEvent& eventToRailCollisionEvent(Event &event);

PocketedEvent& eventToPocketedEvent(Event &event);

CueStrikeEvent& eventToCueStrikeEvent(Event &event);

/** Detailed result of a simulation of a shot.
 * Public objects of this class can only be created by TableState::executeShot()
 * Constructing a Shot object starts the physics simulation.
 * The private methods in this class implement the main part of the physics
 * simulation.
 */
class Shot {
public:
  friend class TableState;

  /** Gets the list of events generated during the shot.
   * The vector is sorted by time, and all relevant ball information is
   * available in the events.
   */
  const std::vector<Event *> &getEventList() const { return shotEvents; }
  /** Returns the amount of time (in seconds) balls will take to settle after
   * executing the shot. */
  double getDuration() const;

  /** Destroy a shot object.
   * Deleting the Shot object is caller's responsibility.
   */
  ~Shot();

private:
  // Uncopiable
  Shot(const Shot &rhs);
  Shot &operator=(const Shot &rhs);

#ifndef SWIG
  std::vector<Event *> shotEvents;

  // Can throw BadShotException from simulateShot
  Shot(TableState &state, const ShotParams &sp,
       bool fullSim /* false = get first ball hit only */, bool verbose = false,
       bool errors = false)
      : shotEvents() {
    simulateShot(state, sp, fullSim, verbose, errors);
  }

  // Can throw BadShotException
  void simulateShot(TableState &state, const ShotParams &sp, bool fullSim,
                    bool verbose, bool errors);

  static bool VERBOSE;
  static bool CHECK_ERRORS;
  static void updateTime(TableState &state, double oldTime, double newTime);
  static void updateBall(const Table &table, Ball &ball, double oldTime,
                         double newTime);
  static double updateSpinning(double w_z, double t, double mu_sp, double R,
                               bool isSliding);

  static void removeRelatedEvents(std::list<Event *> &events, Event *lastEvent);
  static void addRelatedFutureEvents(TableState &state, double curTime,
                                     std::list<Event *> &futureEvents, Ball::Type b1,
                                     Ball::Type b2);
  static Event *nextTransitionEvent(const Table &table, Ball &ball,
                                    double curTime);
  static Event *nextCollisionEvent(const Table &table, Ball &ball1, Ball &ball2,
                                   double curTime);
  static void addBoundaryEvents(const Table &table, Ball &ball, double curTime,
                                std::list<Event *> &futureEvents);
  static double calcEventTime(int numRoots, double root1, double root2,
                              double curTime);

  static int solveQuartic(double roots[], double a0, double a1, double a2,
                          double a3, double a4);
  static constexpr double NEAR_FUTURE_EPSILON = 1E-8;
  static double leastPositiveRealRoot(double roots[],
                                      double epsilon = NEAR_FUTURE_EPSILON);

/*
   static void handleEvent(TableState &state, Event *event);
   static void handleStateChange(Ball &ball);
   static void handleBallCollision(Ball &ball1, Ball &ball2);
   static void handleRailCollision(Ball &ball, Table::BoundaryId rail);
   static void handlePocketed(Ball &ball, Table::Pocket pocket);
   static void handleCueStrike(Ball &ball, const ShotParams &sp);
   */

// static void addFutureEvents(TableState &state, double curTime, std::list<Event*>
// &futureEvents);

// static constexpr double BALL_MASS = 160.0; //From Marlow, in line with BCA
// rules
// static constexpr double g = GSL_CONST_MKSA_GRAV_ACCEL;
// static constexpr double R = 0.028575; //Ball radius //Now taken from
// Ball::BALL_RADIUS
// static constexpr int NUM_BALLS = 16; //Now taken from
// TableState::getNumBalls()
#endif /* ! SWIG */
};
#ifndef SWIG
/** Print a human-readable representation of the shot to a stream */
std::ostream &operator<<(std::ostream &out, Shot &rhs); // doesn't need to be friend
#endif                                        /* ! SWIG */

/** The physical state of balls on a table.
 *  Includes position and velocity information but no rules related information.
 */
class TableState {
public:
  /* Thresholds */
  static constexpr double MAX_VELOCITY =
      10; /**< maximum velocity allowed [m/s]  */
  static constexpr double MIN_THETA =
      0.0; /**< minimum theta allowed [degrees] */
  static constexpr double MAX_THETA =
      70.0; /**< maximum theta allowed [degrees] */

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes). It
   *	indicates that all shot parameters are valid; the actual integer
   *returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int OK_PRECONDITION = 0;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that shot parameter 'a' is invalid or not physically possible;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BAD_A_VAL = 1;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that shot parameter 'b' is invalid or not physically possible;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BAD_B_VAL = 2;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that shot parameter 'theta' is invalid or not physically
   *possible;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BAD_THETA_VAL = 4;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that shot parameter 'phi' is invalid or not physically
   *possible;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BAD_PHI_VAL = 8;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that shot parameter 'V' is invalid or not physically possible;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BAD_V_VAL = 16;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that the cue ball placement x-coordinate is out of range;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BAD_X_VAL = 32;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that the cue ball placement y-coordinate is out of range;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BAD_Y_VAL = 64;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that the cue will collide with a ball before striking the cue
   *ball;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int CUE_STICK_COLLISION = 128;

  /** This integer is used within the bitmask integer returned by
   *Table::isPhysicallyPossible()
   *	and Table::isValidBallPlacement() (as well as the fizG versions of those
   *classes).  It
   *	indicates that the ball placement x-y coordinates result in an overlap
   *with another ball on table;
   *	the actual integer returned by these methods
   *	is simply the OR'ed combinations of the all the possibilities from the
   *list under the heading
   *	'Variables' in the HTML documentation or listed below in the header
   *file; you can AND the result
   *	returned by these methods with any of the possibilities from the list
   *below to test if that
   *	particular possibility is true.  */
  static constexpr int BALL_OVERLAP = 256;

  /** Create an empty table state for given table (or default table if not
   * specified) */
  TableState(const Table &table = Table::defaultTable())
      : _table(table), balls() {}
  /** Copy constructor */
  TableState(const TableState &rhs) : _table(rhs._table), balls(rhs.balls) {}
#ifndef SWIG
  /** Assignment operator */
  TableState &operator=(const TableState &rhs);
#endif /* ! SWIG */

  /** Return the number of different balls used in representing this state */
  int getNumBalls() const { return balls.size(); }
#ifndef SWIG
  /** Iterator for start of ball vector */
  std::vector<Ball>::iterator getBegin() { return balls.begin(); }
  /** Iterator for end of ball vector */
  std::vector<Ball>::iterator getEnd() { return balls.end(); }
  /** Const Iterator for start of ball vector */
  std::vector<Ball>::const_iterator getBegin() const { return balls.begin(); }
  /** Const Iterator for end of ball vector */
  std::vector<Ball>::const_iterator getEnd() const { return balls.end(); }

#endif /* ! SWIG */
  void fixOverlap(const bool VERBOSE);
  /** Modify specified ball id with specified ball information, adding if needed
   */
  void setBall(Ball &b);
  /** Set a ball's state and position, adding if needed */
  void setBall(Ball::Type btype, Ball::State state, Point r);
  /** Set a ball's state and position, adding if needed */
  void setBall(Ball::Type btype, Ball::State state, double x, double y);
  /** Spot a pocketed ball at or near the foot spot, with dithering if needed */
  void spotBall(Ball::Type btype, double dither = DITHER);
  /** Get ball information based on id. If ball does not exist it will be added
   * with unknown information.
   * Returned ball may be modified and will affect the table state.
   */
  Ball &getBall(Ball::Type btype);
#ifndef SWIG
  /** Get ball information based on id. If ball does not exist it will be added
   * with unknown information. */
  const Ball &getBall(Ball::Type btype) const;
#endif /* SWIG */

  /** Return the underlying table object */
  const Table &getTable() const { return _table; };

  /* Validity checkers */

  /** Returns BAD_X_VAL or BAD_Y_VAL if any ball that is in play is off the
   *table or
   *	BALL_OVERLAP if any ball is overlapping with another ball.
   *	Used to check cue ball placement validity in the case of Ball In Hand,
   *for example.
   *	@param VERBOSE Print debugging information */
  int isValidBallPlacement(bool VERBOSE = false) const;

  /** Checks physical validity of the given shot parameters and table state.
   *Used before calling
   *	executeShot() to double-check that an error condition will not result
   *due to invalid
   *	parameters.
   *  @param shotParams Shot parameters
   *	@param VERBOSE Print debugging information
   */
  int isPhysicallyPossible(const ShotParams &shotParams,
                           bool VERBOSE = false) const;

  /** Add racking noise to table state.
   * This has nothing to do with shot execution noise.
   */
  void addNoise(double dither);
  /** Randomly position all balls on the table. */
  void randomize();

#ifdef SWIG
  %exception {
    try {
      $function
    } catch (Pool::BadShotException &ex) {
      std::string msg = "Bad Shot: " + ex.getTypeString();
      SWIG_exception(SWIG_ValueError, msg.c_str());
    }
  }

  %newobject executeShot;
#endif /* SWIG */
       /** Execute given shot on the table state.
        * The TableState object will be modified to reflect the final state of the
        * shot.
        * If you need to retain the initial state, copy the object before calling.
        * Noise is not added to the shot prior to execution.
        * @param sp The shot parameters to execute.
        * @param verbose Print a lot of debugging information to cerr.
        * @param errors Detect internal errors (slower execution)
        * @exception BadShotException will be thrown in case of bad parameters or
        * errors in execution.
        */
  Shot *executeShot(const ShotParams &sp, bool verbose = false,
                    bool errors = false) {
    return new Shot(*this, sp, true, verbose, errors);
  }

#ifdef SWIG
  %exception;
#endif /* SWIG */

  // Returns the first ball that will be hit by the cue ball by the given shot.
  // If the cue ball doesn't hit another ball, returns CUE.
  // Can throw BadShotException from creating Shot
  /** Return the first ball hit by the cue ball while executing shot.
   * This function will simulate the shot up until the first ball is hit by
   * the cue ball and then return the ball type, or UNKNOWN_ID if no ball is
   * hit.
   */
  Ball::Type getFirstBallHit(const ShotParams &sp);

#ifndef SWIG
  /** Writes a machine-readable representation of the table state to a stream.
   */
  void toStream(std::ostream &out) const;
  /** Reads a machine-readable representation of the table state from a stream.
   * Should be used on output of toStream() or toString().
   */
  void fromStream(std::istream &in);
#endif /* ! SWIG */
  /** Returns a machine-readable representation of the table state as a string*/
  std::string toString() const;
  /** Reads a machine-readable representation of the table state from a string.
   * Should be used on output of toStream() or toString().
   */
  void fromString(const std::string &s);
#ifndef SWIG

private:
  const Table &_table;
  std::vector<Ball> balls;

  static constexpr double DITHER = 0.00005;
  static constexpr double EPSILON_B = 0.001; /**< small value added to the b
                                                shot parameter for threshold
                                                calculations [mm] */
  static constexpr double EPSILON_THETA =
      0.001; /**< small value added to the theta shot parameter for threshold
                calculations [degrees] */
  static constexpr int MAX_BALLS_ON_TABLE =
      100; /**< Maximum balls allowed on the table at any time. */

  static int numLineSphereIntersections(Vector &p1, Vector &p2, Vector &p3,
                                        double rad, double &root1,
                                        double &root2);
  int findOverlap(Ball::Type ball) const;
#endif /* ! SWIG */
};
#ifndef SWIG
std::ostream &operator<<(std::ostream &out, TableState &rhs); // doesn't need to be friend
#endif                                              /* ! SWIG */

/** Return a string identifying the version and build information of the library
 */
std::string getFastFizVersion();
#ifndef SWIG
/** Return a string identifying the version and build information of the
 * library.
 *  @deprecated Use getFastFizVersion().
 */
inline std::string getPoolfizVersion() { return getFastFizVersion(); }
#endif /* ! SWIG */

#ifndef SWIG
/** Rack table state for Eight-ball. Debugging function.
 * @deprecated Use the GameState framework to generate a racked state.
 */
void rack(TableState &ts);
/** Dump event list to standard error. Debugging function.
*/
void printEvents(std::list<Event *> events);
/** Print overlapping balls in table state. Debugging function.
*/
void printOverlap(TableState &ts);
#else  /* SWIG */
%newobject getTestState;
#endif /* SWIG */
/** Return a racked state for testing purposes. Debugging function. */
TableState *getTestState();
#ifdef SWIG
%newobject getTestShotParams();
#endif /* SWIG */
/** Return sample shot parameters that work with the test state. */
ShotParams *getTestShotParams();

} // namespace Pool

#ifdef SWIG
%include "std_vector.i"
namespace std {
  %template(EventVector) std::vector<Pool::Event *>;
}
#endif /* SWIG */

#endif //_FastFiz_h


////////////////////////////////////////////////////////////
//
// Copyright (c) 2018 Jan Filipowicz, Filip Turobos
//
// 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.
//
////////////////////////////////////////////////////////////

#ifndef GENETIC_ALGORITHM_LIBRARY_GENETIC_ALGORITHM_H
#define GENETIC_ALGORITHM_LIBRARY_GENETIC_ALGORITHM_H

#include <algorithm>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
#include <gsl/gsl_assert>
#include "evaluated_specimen.h"
#include "repeat.h"

template<class Specimen, class Rating>
class genetic_algorithm {
public:
	using specimen_type = Specimen;
	using rating_type = Rating;
	using evaluated_specimen_type = evaluated_specimen<Specimen, Rating>;
	struct context_type;
	enum struct stage_type { generated, selected, bred };
	explicit genetic_algorithm(const context_type& context);
	explicit genetic_algorithm(context_type&& context);
	template<class... Functions>
	evaluated_specimen_type operator()(Functions&&... observers) const;
private:
	template<class... Functions>
	void communicate_stage(stage_type stage, const std::vector<evaluated_specimen_type>& specimens, Functions&&... observers) const;
	void evaluate(std::vector<evaluated_specimen_type>& specimens) const;
	std::vector<evaluated_specimen_type> breed(const std::vector<evaluated_specimen_type>& specimens) const;
	context_type context;
};

template<class Specimen, class Rating>
struct genetic_algorithm<Specimen, Rating>::context_type {
	std::size_t initial_population_size = 1;
	std::size_t breeding_population_size = 1;
	std::size_t max_iterations = 0;
	std::function<specimen_type()> generator;
	std::function<rating_type(const specimen_type&)> evaluator;
	std::function<void(std::vector<evaluated_specimen_type>&, std::size_t)> selector;
	std::function<specimen_type(const specimen_type&, const specimen_type&)> breeder;
	std::function<bool(rating_type, rating_type)> comparator;
};

template<class Context>
constexpr bool valid(const Context& context) noexcept {
	return context.initial_population_size > 0
		&& context.breeding_population_size > 0
		&& context.generator != nullptr
		&& context.evaluator != nullptr
		&& context.selector != nullptr
		&& context.breeder != nullptr
		&& context.comparator != nullptr
	;
}

template<class Specimen, class Rating>
inline genetic_algorithm<Specimen, Rating>::genetic_algorithm(const context_type& context)
	: context(context) {}

template<class Specimen, class Rating>
inline genetic_algorithm<Specimen, Rating>::genetic_algorithm(context_type&& context)
	: context(std::move(context)) {}

template<class Specimen, class Rating>
template<class... Functions>
inline auto genetic_algorithm<Specimen, Rating>::operator()(Functions&&... observers) const -> evaluated_specimen_type {
	Expects(valid(context));
	std::vector<evaluated_specimen_type> specimens(context.initial_population_size);
	for (auto&& specimen : specimens) {
		specimen.value() = context.generator();
	}
	evaluate(specimens);
	communicate_stage(stage_type::generated, specimens, std::forward<Functions>(observers)...);
	repeat(context.max_iterations, [&] {
		context.selector(specimens, context.breeding_population_size);
		communicate_stage(stage_type::selected, specimens, std::forward<Functions>(observers)...);
		specimens = breed(specimens);
		evaluate(specimens);
		communicate_stage(stage_type::bred, specimens, std::forward<Functions>(observers)...);
	});
	return std::move(*std::max_element(specimens.begin(), specimens.end(), [this](const evaluated_specimen_type& lhs, const evaluated_specimen_type& rhs) {
		return context.comparator(lhs.rating(), rhs.rating());
	}));
}

template<class Specimen, class Rating>
template<class... Functions>
inline void genetic_algorithm<Specimen, Rating>::communicate_stage(stage_type stage, const std::vector<evaluated_specimen_type>& specimens, Functions&&... observers) const {
	(void)stage;
	(void)specimens;
	((void)observers(*this, stage, specimens), ...);
}

template<class Specimen, class Rating>
inline void genetic_algorithm<Specimen, Rating>::evaluate(std::vector<evaluated_specimen_type>& specimens) const {
	for (auto&& specimen : specimens) {
		specimen.evaluate(context.evaluator);
	}
}

template<class Specimen, class Rating>
inline auto genetic_algorithm<Specimen, Rating>::breed(const std::vector<evaluated_specimen_type>& specimens) const -> std::vector<evaluated_specimen_type> {
	const std::size_t specimen_count = specimens.size();
	std::vector<evaluated_specimen_type> result;
	const std::size_t reserve = specimen_count * (specimen_count - 1) / 2;
	result.reserve(reserve);
	for (auto it = specimens.begin(); it != specimens.end(); ++it) {
		const specimen_type& father = it->value();
		std::for_each(std::next(it), specimens.end(), [&](const evaluated_specimen_type& mother) {
			result.emplace_back(evaluated_specimen_type {context.breeder(father, mother.value())});
		});
	}
	Ensures(result.size() == reserve);
	return result;
}

#endif


#include "tmcoct.h"
#include <gsl/gsl_rng.h>

const double G_COS_0_D = 1.0 - 1.0E-14;
const double G_COS_90_D = 1.0E-7;

#define STANDARDTEST 0
/* testing program using fixed rnd seed. */

#define PARTIALREFLECTION 1
/* 1=split photon, 0=statistical reflection. */

#define COSZERO (1.0-1.0E-14)
/* cosine of about 1e-6 rad. */

#define COS90D  1.0E-6
/* cosine of about 1.57 - 1e-6 rad. */

const gsl_rng_type *T_RNG_GSL;
gsl_rng *r_RNG_GSL;

/***********************************************************
 *	A random number generator from Numerical Recipes in C.
 ****/
#define MBIG 1000000000
#define MSEED 161803398
#define MZ 0
#define FAC 1.0E-9

#undef MBIG
#undef MSEED
#undef MZ
#undef FAC

/***********************************************************
 *	Generate a random number between 0 and 1.  Take a
 *	number as seed the first time entering the function.
 *	The seed is limited to 1<<15.
 *	We found that when idum is too large, ran3 may return
 *	numbers beyond 0 and 1.
 ****/
double RandomNum(void) {
    static Boolean first_time = 1;
    static unsigned long int idum;    /* seed for ran3. */

    if (first_time) {
        T_RNG_GSL = gsl_rng_default;
        r_RNG_GSL = gsl_rng_alloc(T_RNG_GSL);

#if STANDARDTEST /* Use fixed seed to test the program. */
        printf("*** Using seed to test. ***\n");
    printf("*** Remove the fixed seed after the test. ***\n");
    idum =  7923;

#else
        idum = (unsigned long int) time(NULL) % (1 << 15);
        /* use 16-bit integer as the seed. */
#endif
        printf("Random seed = %lu \n", idum);

        //ran3(&idum);
        gsl_rng_set(r_RNG_GSL, idum);

        first_time = 0;
        //idum = 1;
    }
    // TODO FIXME remove 1.0 -
    return (1.0 - gsl_rng_uniform(r_RNG_GSL));
}

/***********************************************************
 *	Compute the specular reflection.
 *
 *	If the first layer is a turbid medium, use the Fresnel
 *	reflection from the boundary of the first layer as the
 *	specular reflectance.
 *
 *	If the first layer is glass, multiple reflections in
 *	the first layer is considered to get the specular
 *	reflectance.
 *
 *	The subroutine assumes the Layerspecs array is correctly
 *	initialized.
 ****/
double Rspecular(double ni, double nt) {
    double r1;
    /* direct reflections from the 1st and 2nd layers. */
    double temp;
    temp = (ni - nt) / (ni + nt);
    r1 = temp * temp;
    return (r1);
}

/***********************************************************
 *	Initialize a photon packet.
 ****/
void LaunchPhoton(SimulationStruct *in_parm, double Rspecular, TetrahedronPhotonStruct *Photon_Ptr,
                  TetrahedronPhotonStruct *PhotonCont_Ptr, TetrahedronStruct *TetrahedronRoot) {
    if (Photon_Ptr->FstBackReflectionFlag) {
        //Most often case for biased simulations
        //The photon will be re-initialized from where the bias was applied
        long double LikelihoodRatioTmp = Photon_Ptr->LikelihoodRatioAfterFstBias;
        CopyPhotonStruct(PhotonCont_Ptr, Photon_Ptr);

        //Apply one unbiased random scatter to the split photon
        Spin(regionspecs[Photon_Ptr->tetrahedron->region].g, Photon_Ptr);

        if (LikelihoodRatioTmp < 1)
            // Adjust the likelihoodRation to make the simulation unbiased
            Photon_Ptr->LikelihoodRatio = 1 - LikelihoodRatioTmp;
        else
            Photon_Ptr->LikelihoodRatio = 1;

    } else {

        Photon_Ptr->w = 1.0 - Rspecular;

        Photon_Ptr->x = in_parm->probe_x;
        Photon_Ptr->y = in_parm->probe_y;
        Photon_Ptr->z = in_parm->probe_z;

        Photon_Ptr->s = 0.0;
        Photon_Ptr->sleft = 0.0;

        Photon_Ptr->ux = Photon_Ptr->uy = 0.0;
        Photon_Ptr->uz = 1.0;
        Photon_Ptr->dead = 0.0;

        Photon_Ptr->OpticalPath = 0.0;
        Photon_Ptr->MaxDepth = 0.0;
        Photon_Ptr->LikelihoodRatio = 1.0;
        Photon_Ptr->LikelihoodRatioAfterFstBias = 1.0;

        Photon_Ptr->FstBackReflectionFlag = 0;
        Photon_Ptr->LocationFstBias = -1.0;
        Photon_Ptr->NumBackwardsSpecularReflections = 0;

        Photon_Ptr->LikelihoodRatioIncreaseFstBias = 0;

        Photon_Ptr->LikelihoodRatioIncreaseFstBias = 0;

        Photon_Ptr->NextTetrahedron = -1;

        Photon_Ptr->tetrahedron = TetrahedronRoot;
    }
}

/***********************************************************
 *	Choose (sample) a new theta angle for photon propagation
 *	according to the anisotropy.
 *
 *	If anisotropy g is 0, then
 *		cos(theta) = 2*rand-1.
 *	otherwise
 *		sample according to the Henyey-Greenstein function.
 *
 *	Returns the cosine of the polar deflection angle theta.
 ****/
double SpinTheta(double g) {
    double cost;

    if (g == 0.0)
        cost = 2.0 * RandomNum() - 1.0;
    else {
        double temp = (1.0 - g * g) / (1.0 - g + 2.0 * g * RandomNum());
        cost = (1.0 + g * g - temp * temp) / (2.0 * g);
        if (cost < -1.0) cost = -1.0;
        else if (cost > 1.0) cost = 1.0;
    }
    return (cost);
}

double SpinThetaForwardFstBias(double g) {
    double cost;

    if (g == 0.0)
        cost = RandomNum();
    else {
        double RandomNumTmp = RandomNum();
        double temp = RandomNumTmp / (1 - g) + (1 - RandomNumTmp) / sqrt(g * g + 1);
        cost = (g * g + 1 - 1. / (temp * temp)) / (2 * g);
        if (cost < -1) cost = -1;
        else if (cost > 1) cost = 1;
    }
    return (cost);
}

/***********************************************************
 *	Choose a new direction for photon propagation by
 *	sampling the polar deflection angle theta and the
 *	azimuthal angle psi.
 *
 *	Note:
 *  	theta: 0 - pi so sin(theta) is always positive
 *  	feel free to use sqrt() for cos(theta).
 *
 *  	psi:   0 - 2pi
 *  	for 0-pi  sin(psi) is +
 *  	for pi-2pi sin(psi) is -
 ****/

void Spin(double g,
          TetrahedronPhotonStruct *Photon_Ptr) {
    double cost, sint;    /* cosine and sine of the */
    /* polar deflection angle theta. */
    double cosp, sinp;    /* cosine and sine of the */
    /* azimuthal angle psi. */
    double ux = Photon_Ptr->ux;
    double uy = Photon_Ptr->uy;
    double uz = Photon_Ptr->uz;
    double psi;

    cost = SpinTheta(g);
    sint = sqrt(1.0 - cost * cost);
    /* sqrt() is faster than sin(). */

    psi = 2.0 * PI * RandomNum(); /* spin psi 0-2pi. */
    cosp = cos(psi);
    if (psi < PI)
        sinp = sqrt(1.0 - cosp * cosp);
        /* sqrt() is faster than sin(). */
    else
        sinp = -sqrt(1.0 - cosp * cosp);

    if (fabs(uz) > COSZERO) {    /* normal incident. */
        Photon_Ptr->ux = sint * cosp;
        Photon_Ptr->uy = sint * sinp;
        Photon_Ptr->uz = cost * SIGN(uz);
        /* SIGN() is faster than division. */
    } else {
        /* regular incident. */
        double temp = sqrt(1.0 - uz * uz);
        Photon_Ptr->ux = sint * (ux * uz * cosp - uy * sinp)
                         / temp + ux * cost;
        Photon_Ptr->uy = sint * (uy * uz * cosp + ux * sinp)
                         / temp + uy * cost;
        Photon_Ptr->uz = -sint * cosp * temp + uz * cost;
    }

}

void SpinBias37(double g,
                TetrahedronPhotonStruct *Photon_Ptr,
                TetrahedronPhotonStruct *PhotonCont_Ptr,
                SimulationStruct *In_Ptr)
{
    double g_squared = sq(g);

    double cost, sint;    /* cosine and sine of the */
    /* polar deflection angle theta. */
    double cosp, sinp;    /* cosine and sine of the */
    /* azimuthal angle psi. */
    double ux = Photon_Ptr->ux;
    double uy = Photon_Ptr->uy;
    double uz = Photon_Ptr->uz;
    double ux_Orig = ux;
    double uy_Orig = uy;
    double uz_Orig = uz;
    double psi;

    double BackwardBiasCoefficient = In_Ptr->BackwardBiasCoefficient;
    double costg;
    double costg1, costg2;

    double BiasCoefficientTmp = 0;

    short int ReachedTargetOpticalDepthFlag = 0;
    short int ThisIsFirstBackwardBiasFlag = 0;

    if (Photon_Ptr->z > In_Ptr->TargetDepthMin
        && Photon_Ptr->z < In_Ptr->TargetDepthMax
        && Photon_Ptr->uz > 0
        && !Photon_Ptr->FstBackReflectionFlag) {
        // The bias backwards will be applied only if the photon is going forward
        // The status of the photon prior to the bias will be saved

        CopyPhotonStruct(Photon_Ptr, PhotonCont_Ptr);
        ReachedTargetOpticalDepthFlag = 1;
        Photon_Ptr->FstBackReflectionFlag = 1; // Bias backwards only once
        Photon_Ptr->LocationFstBias = Photon_Ptr->z;
        BiasCoefficientTmp = BackwardBiasCoefficient;
        ThisIsFirstBackwardBiasFlag = 1;
    }

    /**********************************
	 ** Biased Direction towards probe
	 **********************************/
    double vx = In_Ptr->probe_x-Photon_Ptr->x;
    double vy = In_Ptr->probe_y-Photon_Ptr->y;
    double vz = In_Ptr->probe_z-Photon_Ptr->z;
    double LengthVector = sqrt(sq(vx) + sq(vy) + sq(vz));
    vx /= LengthVector;
    vy /= LengthVector;
    vz /= LengthVector;
    /*********************************/

    if ((Photon_Ptr->FstBackReflectionFlag
         || Photon_Ptr->NumBackwardsSpecularReflections > 0)
        && !ReachedTargetOpticalDepthFlag)
    {
        // It was biased at least once before, and is moving backwards
        ReachedTargetOpticalDepthFlag = 2;

        double NextStepSize = -log(In_Ptr->rndStepSizeInTissue) / regionspecs[Photon_Ptr->tetrahedron->region].muas;
        double CurrentDistanceToOrigin = sqrt(sq(Photon_Ptr->x-In_Ptr->probe_x) + sq(Photon_Ptr->y-In_Ptr->probe_y) + sq(Photon_Ptr->z-In_Ptr->probe_z));

        if (NextStepSize >= CurrentDistanceToOrigin
            && acos(-vz) <= In_Ptr->MaxCollectingAngleDeg * PI / 180) {
            ReachedTargetOpticalDepthFlag = 1;
        }

        BiasCoefficientTmp = BackwardBiasCoefficient;

    }

    int BiasFunctionRandomlySelected = 0;
    if (ReachedTargetOpticalDepthFlag) {
        // Photon reached target optical layer or may undergo an additional biased
        // scattering or unbiased scattering

        // BiasFunctionRandomlySelected=1 means use biased scattering and 2 means unbiased scattering
        if (RandomNum() <= In_Ptr->ProbabilityAdditionalBias)
            BiasFunctionRandomlySelected = 1;
        else
            BiasFunctionRandomlySelected = 2;

        if (ReachedTargetOpticalDepthFlag == 1
            || BiasFunctionRandomlySelected == 1) {
            /*************************************************************************
			** The photon is within the target depth and going forward
			** The additional biased scattering is randomly chosen
			** So the scattering is biased Henyey-Greenstein scattering
			*************************************************************************/
            cost = SpinThetaForwardFstBias(BiasCoefficientTmp);
            ux = vx;
            uy = vy;
            uz = vz;
        } else {
            /**************************************************************************************
			** The photon is within the target depth but the scattering is randomly selected is
			** unbiased scattering
			** or the photon is already going backward or it is out of target depth
			**************************************************************************************/
            cost = SpinTheta(g);
        }
    } else {
        /**************************************************************************
		**  The photon is not within the target depth or it is not going forward
		**  so do unbiased scattering
		**************************************************************************/
        cost = SpinTheta(g);
    }

    if (cost < -1)
        cost = -1;
    else if (cost > 1)
        cost = 1;

    sint = sqrt(1.0 - cost * cost);
    /* sqrt() is faster than sin(). */

    psi = 2.0 * PI * RandomNum(); /* spin psi 0-2pi. */
    cosp = cos(psi);
    if (psi < PI)
        sinp = sqrt(1.0 - cosp * cosp);
        /* sqrt() is faster than sin(). */
    else
        sinp = -sqrt(1.0 - cosp * cosp);

    if (fabs(uz) > COSZERO) {    /* normal incident. */
        Photon_Ptr->ux = sint * cosp;
        Photon_Ptr->uy = sint * sinp;
        Photon_Ptr->uz = cost * SIGN(uz);
        /* SIGN() is faster than division. */
    } else {        /* regular incident. */
        double temp = sqrt(1.0 - uz * uz);
        Photon_Ptr->ux = sint * (ux * uz * cosp - uy * sinp)
                         / temp + ux * cost;
        Photon_Ptr->uy = sint * (uy * uz * cosp + ux * sinp)
                         / temp + uy * cost;
        Photon_Ptr->uz = -sint * cosp * temp + uz * cost;
    }

    costg = ux_Orig * Photon_Ptr->ux
            + uy_Orig * Photon_Ptr->uy
            + uz_Orig * Photon_Ptr->uz;
    costg2 = costg;
    costg1 = vx * Photon_Ptr->ux
             + vy * Photon_Ptr->uy
             + vz * Photon_Ptr->uz;

    if (BiasCoefficientTmp) {
        double one_plus_a_squared = 1 + sq(BiasCoefficientTmp);
        double sqrt_one_plus_a_squared = sqrt(one_plus_a_squared);
        double LikelihoodRatioIncreaseFactor;
        if (ReachedTargetOpticalDepthFlag == 1)
            /****************************************************************************************
			 ** Likelihood for the first Bias scattering. Equation (8) of the paper:
			 ** Malektaji, Siavash, Ivan T. Lima, and Sherif S. Sherif. "Monte Carlo simulation of
			 ** optical coherence tomography for turbid media with arbitrary spatial distributions."
			 ** Journal of biomedical optics 19.4 (2014): 046001-046001.
			 ****************************************************************************************/
            LikelihoodRatioIncreaseFactor = ((1.0 - g_squared) * (sqrt_one_plus_a_squared - 1.0 + BiasCoefficientTmp) *
                                             sqrt(cube(one_plus_a_squared - 2.0 * BiasCoefficientTmp * cost))) /
                                            (2.0 * BiasCoefficientTmp * (1.0 - BiasCoefficientTmp) *
                                             sqrt_one_plus_a_squared * sqrt(cube(1.0 + g_squared - 2.0 * g * costg)));
        else {
            double cost1, cost2;
            if (BiasFunctionRandomlySelected == 1) {
                cost1 = cost;
                cost2 = costg2;
            } else {
                cost1 = costg1;
                cost2 = cost;
            }
            /*******************************************************************************************************
			 **  The likelihood ratio of additional biased scatterings, whether the biased or the unbiased
			 **  probability density function is randomly selected, is calculated according to the equation (9)
			 **  of the paper:
			 **  Malektaji, Siavash, Ivan T. Lima, and Sherif S. Sherif. "Monte Carlo simulation of
			 **  optical coherence tomography for turbid media with arbitrary spatial distributions."
			 **  Journal of biomedical optics 19.4 (2014): 046001-046001.
			 *******************************************************************************************************/
            double pdf1 = (sqrt_one_plus_a_squared * BiasCoefficientTmp * (1.0 - BiasCoefficientTmp)) /
                          ((sqrt_one_plus_a_squared - 1.0 + BiasCoefficientTmp) *
                           sqrt(cube(one_plus_a_squared - 2.0 * BiasCoefficientTmp * cost1)));

            double pdf2 = (1.0 - g_squared) / (2.0 * cube(sqrt(1.0 + g_squared - 2.0 * g * cost2)));

            LikelihoodRatioIncreaseFactor = pdf2 /
                                            (In_Ptr->ProbabilityAdditionalBias * pdf1 +
                                             (1.0 - In_Ptr->ProbabilityAdditionalBias) * pdf2);

        }

        Photon_Ptr->LikelihoodRatio *= LikelihoodRatioIncreaseFactor;
        if (ThisIsFirstBackwardBiasFlag == 1) {
            // In case there was a sure backward bias and that was the very first one
            Photon_Ptr->LikelihoodRatioAfterFstBias = Photon_Ptr->LikelihoodRatio;
            Photon_Ptr->LikelihoodRatioIncreaseFstBias = LikelihoodRatioIncreaseFactor;
        }
    }
}

/***********************************************************
 *	Move the photon s away in the current layer of medium.
 ****/
void Hop(TetrahedronPhotonStruct *Photon_Ptr) {
    double s = Photon_Ptr->s;
    Photon_Ptr->x += s * Photon_Ptr->ux;
    Photon_Ptr->y += s * Photon_Ptr->uy;
    Photon_Ptr->z += s * Photon_Ptr->uz;

    Photon_Ptr->OpticalPath += s;
    if (Photon_Ptr->MaxDepth < Photon_Ptr->z)
        Photon_Ptr->MaxDepth = Photon_Ptr->z;
}
/***********************************************************
 *	If uz != 0, return the photon step size in glass,
 *	Otherwise, return 0.
 *
 *	The step size is the distance between the current
 *	position and the boundary in the photon direction.
 *
 *	Make sure uz !=0 before calling this function.
 ****/

/***********************************************************
 *	Pick a step size for a photon packet when it is in
 *	tissue.
 *	If the member sleft is zero, make a new step size
 *	with: -log(rnd)/(mua+mus).
 *	Otherwise, pick up the leftover in sleft.
 *
 *	Layer is the index to layer.
 *	In_Ptr is the input parameters.
 ****/
void StepSizeInTissue(TetrahedronPhotonStruct *Photon_Ptr) {

    if (Photon_Ptr->sleft == 0.0) {  /* make a new step. */
        double rnd;

        do rnd = RandomNum();
        while (rnd <= 0.0);    /* avoid zero. */

        Photon_Ptr->s = -log(rnd) * regionspecs[Photon_Ptr->tetrahedron->region].rmuas;
    } else {    /* take the leftover. */
        Photon_Ptr->s = Photon_Ptr->sleft * regionspecs[Photon_Ptr->tetrahedron->region].rmuas;
        Photon_Ptr->sleft = 0.0;
    }
}

/***********************************************************
 *	Check if the step will hit the boundary.
 *	Return 1 if hit boundary.
 *	Return 0 otherwise.
 *
 * 	If the projected step hits the boundary, the members
 *	s and sleft of Photon_Ptr are updated.
 ****/
Boolean HitBoundary(TetrahedronPhotonStruct *Photon_Ptr) {
    TetrahedronStruct *tetrahedron;
    tetrahedron = Photon_Ptr->tetrahedron;

    double min_distance = 1e10;
    int index_of_tetrahedron_with_min_distance = -1;

    double cos_normals_and_photon_direction[4];
    double distance_from_face_in_photon_direction;
    double perpendicular_distance;

    for (int i = 0; i < 4; i++) {
        cos_normals_and_photon_direction[i] = (Photon_Ptr->tetrahedron->Faces[i].Nx) * Photon_Ptr->ux +
                      (Photon_Ptr->tetrahedron->Faces[i].Ny) * Photon_Ptr->uy +
                      (Photon_Ptr->tetrahedron->Faces[i].Nz) * Photon_Ptr->uz;
    }

    for (int i = 0; i < 4; i++) {
        if (cos_normals_and_photon_direction[i] < 0) {
            perpendicular_distance = ((Photon_Ptr->tetrahedron->Faces[i].Nx) * Photon_Ptr->x +
                      (Photon_Ptr->tetrahedron->Faces[i].Ny) * Photon_Ptr->y +
                      (Photon_Ptr->tetrahedron->Faces[i].Nz) * Photon_Ptr->z + Photon_Ptr->tetrahedron->Faces[i].d);
            distance_from_face_in_photon_direction = -perpendicular_distance / cos_normals_and_photon_direction[i];

            if (distance_from_face_in_photon_direction < min_distance) {
                min_distance = distance_from_face_in_photon_direction;
                index_of_tetrahedron_with_min_distance = i;
                Photon_Ptr->MinCos = cos_normals_and_photon_direction[i];
            }
        }
    }

    Boolean hit_boundary;
    if (Photon_Ptr->s > min_distance) {
        /* not horizontal & crossing. */

        Photon_Ptr->sleft = (Photon_Ptr->s - min_distance) * regionspecs[tetrahedron->region].muas;
        Photon_Ptr->s = min_distance;
        hit_boundary = 1;
        Photon_Ptr->NextTetrahedron = index_of_tetrahedron_with_min_distance;

    } else {

        hit_boundary = 0;
        Photon_Ptr->NextTetrahedron = -1;

    }
    return hit_boundary;
}

/***********************************************************
 *	Drop photon weight inside the tissue (not glass).
 *
 *  The photon is assumed not dead.
 *
 *	The weight drop is dw = w*mua/(mua+mus).
 *
 *	The dropped weight is assigned to the absorption array
 *	elements.
 ****/
void Drop(TetrahedronPhotonStruct *Photon_Ptr) {
    double dwa;    /* absorbed weight.*/
    TetrahedronStruct *tetrahedron = Photon_Ptr->tetrahedron;

    dwa = Photon_Ptr->w * regionspecs[tetrahedron->region].mua_muas;
    Photon_Ptr->w -= dwa;
}

/***********************************************************
 *	The photon weight is small, and the photon packet tries
 *	to survive a roulette.
 ****/
void Roulette(TetrahedronPhotonStruct *Photon_Ptr) {
    if (Photon_Ptr->w == 0.0)
        Photon_Ptr->dead = 1;
    else if (RandomNum() < CHANCE) /* survived the roulette.*/
        Photon_Ptr->w /= CHANCE;
    else
        Photon_Ptr->dead = 1;
}

/***********************************************************
 *	Compute the Fresnel reflectance.
 *
 *	Make sure that the cosine of the incident angle a1
 *	is positive, and the case when the angle is greater
 *	than the critical angle is ruled out.
 *
 * 	Avoid trigonometric function operations as much as
 *	possible, because they are computation-intensive.
 ****/
double
RFresnel(SimulationStruct *In_Ptr, TetrahedronPhotonStruct *Photon_Ptr, double *ux_reflected, double *uy_reflected,
         double *uz_reflected, double *ux_refracted, double *uy_refracted, double *uz_refracted) {

    double r;

    double cosa, sina, sinb, cosb;

    cosa = -(Photon_Ptr->MinCos);

    double ni = regionspecs[Photon_Ptr->tetrahedron->region].n;
    double nt;
    if (Photon_Ptr->tetrahedron->adjTetrahedrons[Photon_Ptr->NextTetrahedron] == NULL)
        nt = regionspecs[0].n;
    else {

        int next_region = Photon_Ptr->tetrahedron->adjTetrahedrons[Photon_Ptr->NextTetrahedron]->region;
        nt = regionspecs[next_region].n;
    }

    sina = sqrt(1.0 - cosa * cosa);
    sinb = ni * sina / nt;
    cosb = sqrt(1.0 - sinb * sinb);

    if (cosa > G_COS_0_D) {
        r = (ni - nt)
            / (ni + nt);
        r *= r;
        cosb = 1;
    } else if (cosa < G_COS_90_D) {
        r = 1.0;
    } else {
        sina = sqrt(1 - cosa * cosa);
        sinb = ni * sina / nt;
        if (sinb >= 1) {
            r = 1.0;
        } else {
            cosb = sqrt(1.0 - sinb * sinb);
            double cosacosb = cosa * cosb;
            double sinasinb = sina * sinb;
            double sinacosb = sina * cosb;
            double cosasinb = cosa * sinb;
            double cap = cosacosb - sinasinb;
            double cam = cosacosb + sinasinb;
            double sap = sinacosb + cosasinb;
            double sam = sinacosb - cosasinb;
            r = 0.5 * sam * sam * (cam * cam + cap * cap) / (sap * sap * cam * cam);
        }
    }

    double sbdivsa = ni / nt;
    *ux_refracted = -cosb * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Nx +
                    sbdivsa * (cosa * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Nx + Photon_Ptr->ux);
    *uy_refracted = -cosb * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Ny +
                    sbdivsa * (cosa * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Ny + Photon_Ptr->uy);
    *uz_refracted = -cosb * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Nz +
                    sbdivsa * (cosa * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Nz + Photon_Ptr->uz);

    *ux_reflected = 2 * cosa * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Nx + Photon_Ptr->ux;
    *uy_reflected = 2 * cosa * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Ny + Photon_Ptr->uy;
    *uz_reflected = 2 * cosa * Photon_Ptr->tetrahedron->Faces[Photon_Ptr->NextTetrahedron].Nz + Photon_Ptr->uz;

    return r;

}

/***********************************************************
 *	Record the photon weight exiting the first layer(uz<0),
 *	no matter whether the layer is glass or not, to the
 *	reflection array.
 *
 *	Update the photon weight as well.
 ***********************************************************/
void RecordValidationR(double Refl, SimulationStruct *In_Ptr, TetrahedronPhotonStruct *Photon_Ptr, OutStruct *Out_Ptr) {
    double x = Photon_Ptr->x;
    double y = Photon_Ptr->y;

    short SpatialFilterFlag = 0;
    if (sqrt(sq(x-In_Ptr->probe_x) + sq(y-In_Ptr->probe_y)) <
        In_Ptr->MaxCollectingRadius        /* The position of photon should be within the radius of the probe */
        && acos(-Photon_Ptr->uz) < In_Ptr->MaxCollectingAngleDeg * PI / 180) {
        if ((In_Ptr->TypeBias == 0 || In_Ptr->TypeBias == 3))
            SpatialFilterFlag = 1;

        if ((Photon_Ptr->FstBackReflectionFlag && In_Ptr->TypeBias == 37 ||
             Photon_Ptr->LocationFstBias == Photon_Ptr->MaxDepth
             && In_Ptr->TypeBias != 37 ||
             Photon_Ptr->NumBackwardsSpecularReflections > 0))
            SpatialFilterFlag = 1;
    }

    if (SpatialFilterFlag) {

        In_Ptr->NumFilteredPhotons++;
        double FilterOpticalPath = Photon_Ptr->OpticalPath;
        double FilterOpticalDepth = FilterOpticalPath / 2.0;

        unsigned int VectorPosition = (unsigned int) (
                (FilterOpticalPath / 2.0 - In_Ptr->OpticalDepthShift)
                / (In_Ptr->CoherenceLengthSource / NUM_SUBSTEPS_RESOLUTION));

        int ii;
        for (ii = VectorPosition - NUM_SUBSTEPS_RESOLUTION / 2;
             ii < VectorPosition + NUM_SUBSTEPS_RESOLUTION / 2;
             ii++) {
            if (ii >= 0 && ii < In_Ptr->NumOpticalDepthLengthSteps) {
                short FilterClassI_Flag =
                        Photon_Ptr->MaxDepth > (FilterOpticalDepth
                                                - In_Ptr->CoherenceLengthSource / 2.0);

                double tmpPhotonContribution = Photon_Ptr->w * (1.0 - Refl) * Photon_Ptr->LikelihoodRatio;
                if (FilterClassI_Flag) {
                    if (ii == VectorPosition)
                        In_Ptr->NumFilteredPhotonsClassI++;
                    Out_Ptr->ReflectanceClassI_Sum[ii] += tmpPhotonContribution;
                    if (Out_Ptr->ReflectanceClassI_Max[ii] < tmpPhotonContribution)
                        Out_Ptr->ReflectanceClassI_Max[ii] = tmpPhotonContribution;
                    Out_Ptr->ReflectanceClassI_SumSq[ii] += sq(tmpPhotonContribution);
                    Out_Ptr->NumClassI_PhotonsFilteredInRange[ii]++;

                } else {
                    if (ii == VectorPosition)
                        In_Ptr->NumFilteredPhotonsClassII++;
                    if (Out_Ptr->ReflectanceClassII_Max[ii] < tmpPhotonContribution)
                        Out_Ptr->ReflectanceClassII_Max[ii] = tmpPhotonContribution;
                    Out_Ptr->ReflectanceClassII_Sum[ii] += tmpPhotonContribution;
                    Out_Ptr->ReflectanceClassII_SumSq[ii] += sq(tmpPhotonContribution);
                    Out_Ptr->NumClassII_PhotonsFilteredInRange[ii]++;

                }
            }
        }
    }

    Photon_Ptr->w *= Refl;

}

/***********************************************************
 *	Decide whether the photon will be transmitted  or be
 *	reflected on the bottom boundary (uz>0) of the current
 *	layer.
 *
 *	If the photon is transmitted, move the photon to
 *	"layer+1". If "layer" is the last layer, record the
 *	transmitted weight as transmittance. See comments for
 *	CrossUpOrNot.
 *
 *	Update the photon parmameters.
 ****/
void CrossOrNot(SimulationStruct *In_Ptr, TetrahedronPhotonStruct *Photon_Ptr, OutStruct *Out_Ptr) {

    double uz_reflected = 0, ux_reflected = 0, uy_reflected = 0;    /* cosines of transmission alpha. */
    double uz_refracted = 0, ux_refracted = 0, uy_refracted = 0;

    double r = 0.0;                        /* reflectance */

    r = RFresnel(In_Ptr, Photon_Ptr, &ux_reflected, &uy_reflected, &uz_reflected, &ux_refracted, &uy_refracted,
                 &uz_refracted);

#if PARTIALREFLECTION
    if (Photon_Ptr->tetrahedron->adjTetrahedrons[Photon_Ptr->NextTetrahedron] == NULL && r < 1.0) { /* We use actual photon splitting if the photon is exiting the media
																							 ** We store the part the is exiting and the rest will be traced */
        Photon_Ptr->ux = ux_refracted;
        Photon_Ptr->uy = uy_refracted;
        Photon_Ptr->uz = uz_refracted;

        if (Photon_Ptr->uz < 0)
            RecordValidationR(r, In_Ptr, Photon_Ptr, Out_Ptr);
        else {
            Photon_Ptr->NumBackwardsSpecularReflections++;
            Photon_Ptr->w *= r;
        }
        Photon_Ptr->ux = ux_reflected;
        Photon_Ptr->uy = uy_reflected;
        Photon_Ptr->uz = uz_reflected;

    }
        /* If photon is not exiting the medium we use the statistical splitting */
    else if (RandomNum() > r) {/* transmitted */

        Photon_Ptr->tetrahedron = Photon_Ptr->tetrahedron->adjTetrahedrons[Photon_Ptr->NextTetrahedron];

        Photon_Ptr->ux = ux_refracted;
        Photon_Ptr->uy = uy_refracted;
        Photon_Ptr->uz = uz_refracted;

        Photon_Ptr->NextTetrahedron = -1;

    } else                        /* reflected. */
    {
        Photon_Ptr->NextTetrahedron = -1;

        if (Photon_Ptr->uz > 0)
            Photon_Ptr->NumBackwardsSpecularReflections++;

        Photon_Ptr->ux = ux_reflected;
        Photon_Ptr->uy = uy_reflected;
        Photon_Ptr->uz = uz_reflected;

    }
#else	/* use just statistical splitting */
    if(RandomNum() > r) {		/* transmitted. */

    if(Photon_Ptr->tetrahedron->adjTetrahedrons[Photon_Ptr->NextTetrahedron]==NULL) {

      Photon_Ptr->ux = ux_refracted;
      Photon_Ptr->uy = uy_refracted;
      Photon_Ptr->uz = uz_refracted;

      if (Photon_Ptr->uz<0)
            RecordValidationR(0.0, In_Ptr, Photon_Ptr, Out_Ptr);

      Photon_Ptr->dead = 1;
    }
    else {

      /* Siavash Refraction Direction Cosines */
      Photon_Ptr->ux = ux_refracted;
      Photon_Ptr->uy = uy_refracted;
      Photon_Ptr->uz = uz_refracted;
      Photon_Ptr->tetrahedron=Photon_Ptr->tetrahedron->adjTetrahedrons[Photon_Ptr->NextTetrahedron];
      Photon_Ptr->NextTetrahedron=-1;
    }
  }
  else {
    /* reflected. */

    Photon_Ptr->ux = ux_reflected;
    Photon_Ptr->uy = uy_reflected;
    Photon_Ptr->uz = uz_reflected;
    Photon_Ptr->NextTetrahedron=-1;
  }
#endif

}

/***********************************************************
 ****/
/***********************************************************
 *	Move the photon packet in glass layer.
 *	Horizontal photons are killed because they will
 *	never interact with tissue again.
 ****/
/***********************************************************
 *	Set a step size, move the photon, drop some weight,
 *	choose a new photon direction for propagation.
 *
 *	When a step size is long enough for the photon to
 *	hit an interface, this step is divided into two steps.
 *	First, move the photon to the boundary free of
 *	absorption or scattering, then decide whether the
 *	photon is reflected or transmitted.
 *	Then move the photon in the current or transmission
 *	medium with the unfinished stepsize to interaction
 *	site.  If the unfinished stepsize is still too long,
 *	repeat the above process.
 ****/
void HopDropSpinInTissue(SimulationStruct *In_Ptr,
                         TetrahedronPhotonStruct *Photon_Ptr,
                         TetrahedronPhotonStruct *PhotonCont_Ptr,
                         OutStruct *Out_Ptr) {
    StepSizeInTissue(Photon_Ptr);
    if (HitBoundary(Photon_Ptr)) {
        Hop(Photon_Ptr);    /* move to boundary plane. */
        CrossOrNot(In_Ptr, Photon_Ptr, Out_Ptr);
    } else {
        Hop(Photon_Ptr);
        Drop(Photon_Ptr);

        switch (In_Ptr->TypeBias) {
            case 0:                        /* No importance sampling */
                Spin(regionspecs[Photon_Ptr->tetrahedron->region].g, Photon_Ptr);
                break;
            case 37:                    /* BOE2 Biasing by Lima et al. */
                SpinBias37(regionspecs[Photon_Ptr->tetrahedron->region].g, Photon_Ptr, PhotonCont_Ptr, In_Ptr);
        }
    }
}

void HopDropSpin(SimulationStruct *In_Ptr, TetrahedronPhotonStruct *Photon_Ptr, TetrahedronPhotonStruct *PhotonCont_Ptr,
                 OutStruct *Out_Ptr) {
    HopDropSpinInTissue(In_Ptr, Photon_Ptr, PhotonCont_Ptr, Out_Ptr);

    if (Photon_Ptr->w < WEIGHT && !Photon_Ptr->dead)
        Roulette(Photon_Ptr);

}

void CopyPhotonStruct(TetrahedronPhotonStruct *OrigPhoton_Ptr, TetrahedronPhotonStruct *DestPhoton_Ptr) {

    DestPhoton_Ptr->x = OrigPhoton_Ptr->x;
    DestPhoton_Ptr->y = OrigPhoton_Ptr->y;
    DestPhoton_Ptr->z = OrigPhoton_Ptr->z;    /* Cartesian coordinates.[cm] */
    DestPhoton_Ptr->ux = OrigPhoton_Ptr->ux;
    DestPhoton_Ptr->uy = OrigPhoton_Ptr->uy;
    DestPhoton_Ptr->uz = OrigPhoton_Ptr->uz;/* directional cosines of a photon. */
    DestPhoton_Ptr->w = OrigPhoton_Ptr->w;            /* weight. */
    DestPhoton_Ptr->dead = OrigPhoton_Ptr->dead;        /* 1 if photon is terminated. */

    DestPhoton_Ptr->MinCos = OrigPhoton_Ptr->MinCos;
    DestPhoton_Ptr->tetrahedron = OrigPhoton_Ptr->tetrahedron;
    DestPhoton_Ptr->NextTetrahedron = OrigPhoton_Ptr->NextTetrahedron;

    DestPhoton_Ptr->s = OrigPhoton_Ptr->s;            /* current step size. [cm]. */
    DestPhoton_Ptr->sleft = OrigPhoton_Ptr->sleft;        /* step size left. dimensionless [-]. */

    DestPhoton_Ptr->OpticalPath = OrigPhoton_Ptr->OpticalPath;
    DestPhoton_Ptr->MaxDepth = OrigPhoton_Ptr->MaxDepth;
    DestPhoton_Ptr->LikelihoodRatio = OrigPhoton_Ptr->LikelihoodRatio;
    DestPhoton_Ptr->FstBackReflectionFlag = OrigPhoton_Ptr->FstBackReflectionFlag;
    DestPhoton_Ptr->LocationFstBias = OrigPhoton_Ptr->LocationFstBias;
    DestPhoton_Ptr->NumBackwardsSpecularReflections = OrigPhoton_Ptr->NumBackwardsSpecularReflections;

}


#ifndef HIC_MPLD_POSTDOC_H
#define HIC_MPLD_POSTDOC_H

#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iostream>
#include <map>
#include <math.h>
//#include <mpi.h>
#include <omp.h>
#include <vector>

#include <gsl/gsl_cdf.h>

#include <../IRLS_glm/IRLS.h>

#include <regionDetail2D_pairSite.hpp>
#include <bothEndsMappedFragInfo_withCuttingSite.hpp>

#include <RInside.h>

#define INTTAG 0
#define BOOLTAG 1
#define DIETAG 2

#define NEIGHBDIS 5
#define MORANI 0.001
#define PCUTOFF 0.004
#define PRECISION 100000

//using namespace std;
using std::abs;
using std::basic_string;
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::exception;
using std::flush;
using std::ifstream;
using std::istringstream;
using std::make_pair;
using std::map;
using std::ofstream;
using std::ostringstream;
using std::pair;
using std::sort;
using std::string;
using std::vector;

int postdoc(vector<double>, map<int, int>, const int, const string);
int receiveDomainMap(vector< pair<int, int> >&);
int write_domainFragInteractionMatrix(map< pair< pair< int, pair<int, int> >, pair< int, pair<int, int> > >, vector<fragInfo_bothEndsMapped_withCuttingSite> >&, map<int, int>&, vector< pair<int, int> >&, int, string&);
int getDomainCSinteractionMatrix(map< pair< pair<int, int>, pair<int, int> >, int >&, map< int, vector<int> >&, vector< pair<int, int> >&, int, vector< vector<int> >&, vector< vector< vector<int> > >&, map< int, map<int, int> >&);
inline int convtIndex(int, int, int);
int findIntraDomainInteraction(string, vector< vector<int> >&, vector< vector< vector<int> > >&, map<int, int>&, map< int, map< pair<int, int>, double > >&);
int outputDomainInfo(string, vector< vector<int> >&, vector< vector< vector<int> > >&, map<int, int>&, map< int, map< pair<int, int>, double > >&);
int findInteractingRegion(int, map< int, map< pair<int, int>, double> >&, vector< vector<int> >&, vector<regionDetail_pairSite_2D>&);
int searchNeighbSites(map< pair<int, int>, double >&, map<int, int>&, int, int, int, int, vector< pair< pair<int, int>, double > >&, int&, double&);
int writer_2Dregion(vector<regionDetail_pairSite_2D>&, const string&);
int glm_lasso_fit(vector<double>&, vector<double>&, vector< vector<double> >&);

#endif


#include <gsl/gsl_math.h>
#include "gsl_cblas.h"
#include "cblas.h"

void
cblas_ssbmv (const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
	     const int N, const int K, const float alpha, const float *A,
	     const int lda, const float *X, const int incX, const float beta,
	     float *Y, const int incY)
{
#define BASE float
#include "source_sbmv.h"
#undef BASE
}