/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                           */
/*                  This file is part of the program                         */
/*          GCG --- Generic Column Generation                                */
/*                  a Dantzig-Wolfe decomposition based extension            */
/*                  of the branch-cut-and-price framework                    */
/*         SCIP --- Solving Constraint Integer Programs                      */
/*                                                                           */
/* Copyright (C) 2010-2018 Operations Research, RWTH Aachen University       */
/*                         Zuse Institute Berlin (ZIB)                       */
/*                                                                           */
/* This program is free software; you can redistribute it and/or             */
/* modify it under the terms of the GNU Lesser General Public License        */
/* as published by the Free Software Foundation; either version 3            */
/* of the License, or (at your option) any later version.                    */
/*                                                                           */
/* This program is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
/* GNU Lesser General Public License for more details.                       */
/*                                                                           */
/* You should have received a copy of the GNU Lesser General Public License  */
/* along with this program; if not, write to the Free Software               */
/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
/*                                                                           */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**@file   sepa_basis.c
 * @brief  basis separator
 * @author Jonas Witt
 */

/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/

/*#define SCIP_DEBUG*/

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "scip/scip.h"
#include "scip/scipdefplugins.h"
#include "sepa_basis.h"
#include "sepa_master.h"
#include "gcg.h"
#include "relax_gcg.h"
#include "pricer_gcg.h"
#include "pub_gcgvar.h"

#ifdef GSL
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_permutation.h>
#include <gsl/gsl_linalg.h>
#endif

#define SEPA_NAME              "basis"
#define SEPA_DESC              "separator calculates a basis of the orig problem to generate cuts, which cut off the master lp sol"
#define SEPA_PRIORITY                100
#define SEPA_FREQ                     0
#define SEPA_MAXBOUNDDIST           1.0
#define SEPA_USESSUBSCIP           FALSE /**< does the separator use a secondary SCIP instance? */
#define SEPA_DELAY                FALSE /**< should separation method be delayed, if other separators found cuts? */

#define STARTMAXCUTS 50       /**< maximal cuts used at the beginning */
#define MAXCUTSINC   20       /**< increase of allowed number of cuts */

/*
 * Data structures
 */

/** separator data */
struct SCIP_SepaData
{
   SCIP_ROW**            mastercuts;         /**< cuts in the master problem */
   SCIP_ROW**            origcuts;           /**< cuts in the original problem */
   int                   norigcuts;          /**< number of cuts in the original problem */
   int                   nmastercuts;        /**< number of cuts in the master problem */
   int                   maxcuts;            /**< maximal number of allowed cuts */
   SCIP_ROW**            newcuts;            /**< new cuts to tighten original problem */
   int                   nnewcuts;           /**< number of new cuts */
   int                   maxnewcuts;         /**< maximal number of allowed new cuts */
   SCIP_ROW*             objrow;             /**< row with obj coefficients */
   SCIP_Bool             enable;             /**< parameter returns if basis separator is enabled */
   SCIP_Bool             enableobj;          /**< parameter returns if objective constraint is enabled */
   SCIP_Bool             enableobjround;     /**< parameter returns if rhs/lhs of objective constraint is rounded, when obj is int */
   SCIP_Bool             enableppcuts;       /**< parameter returns if cuts generated during pricing are added to newconss array */
   SCIP_Bool             enableppobjconss;   /**< parameter returns if objective constraint for each redcost of pp is enabled */
   SCIP_Bool             enableppobjcg;      /**< parameter returns if objective constraint for each redcost of pp is enabled during pricing */
   int                   separationsetting;  /**< parameter returns which parameter setting is used for separation */
   SCIP_Bool             chgobj;             /**< parameter returns if basis is searched with different objective */
   SCIP_Bool             chgobjallways;      /**< parameter returns if obj is not only changed in first iteration */
   SCIP_Bool             genobjconvex;       /**< parameter returns if objconvex is generated dynamically */
   SCIP_Bool             enableposslack;     /**< parameter returns if positive slack should influence the probing objective function */
   SCIP_Bool             forcecuts;          /**< parameter returns if cuts are forced to enter the LP */
   int                   posslackexp;        /**< parameter returns exponent of usage of positive slack */
   SCIP_Bool             posslackexpgen;     /**< parameter returns if exponent should be automatically generated */
   SCIP_Real             posslackexpgenfactor; /**< parameter returns factor for automatically generated exponent */
   int                   iterations;         /**< parameter returns number of new rows adding iterations (rows just cut off probing lp sol) */
   int                   mincuts;            /**< parameter returns number of minimum cuts needed to return *result = SCIP_Separated */
   SCIP_Real             objconvex;          /**< parameter return convex combination factor */
};

/*
 * Local methods
 */

/** allocates enough memory to hold more cuts */
static
SCIP_RETCODE ensureSizeCuts(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_SEPADATA*        sepadata,           /**< separator data data structure */
   int                   size                /**< new size of cut arrays */
   )
{
   assert(scip != NULL);
   assert(sepadata != NULL);
   assert(sepadata->mastercuts != NULL);
   assert(sepadata->origcuts != NULL);
   assert(sepadata->norigcuts <= sepadata->maxcuts);
   assert(sepadata->norigcuts >= 0);
   assert(sepadata->nmastercuts <= sepadata->maxcuts);
   assert(sepadata->nmastercuts >= 0);

   if( sepadata->maxcuts < size )
   {
      while ( sepadata->maxcuts < size )
      {
         sepadata->maxcuts += MAXCUTSINC;
      }
      SCIP_CALL( SCIPreallocMemoryArray(scip, &(sepadata->mastercuts), sepadata->maxcuts) );
      SCIP_CALL( SCIPreallocMemoryArray(scip, &(sepadata->origcuts), sepadata->maxcuts) );
   }
   assert(sepadata->maxcuts >= size);

   return SCIP_OKAY;
}

/** allocates enough memory to hold more new cuts */
static
SCIP_RETCODE ensureSizeNewCuts(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_SEPADATA*        sepadata,           /**< separator data data structure */
   int                   size                /**< new size of cut arrays */
   )
{
   assert(scip != NULL);
   assert(sepadata != NULL);
   assert(sepadata->newcuts != NULL);
   assert(sepadata->nnewcuts <= sepadata->maxnewcuts);
   assert(sepadata->nnewcuts >= 0);

   if( sepadata->maxnewcuts < size )
   {
      while ( sepadata->maxnewcuts < size )
      {
         sepadata->maxnewcuts += MAXCUTSINC;
      }
      SCIP_CALL( SCIPreallocMemoryArray(scip, &(sepadata->newcuts), sepadata->maxnewcuts) );
   }
   assert(sepadata->maxnewcuts >= size);

   return SCIP_OKAY;
}

/** returns the result of the exponentiation for given exponent and basis (basis^exponent) */
static
SCIP_Real exponentiate(
   SCIP_Real            basis,               /**< basis for exponentiation */
   int                  exponent            /**< exponent for exponentiation */
   )
{
   SCIP_Real result;
   int i;

   assert(exponent >= 0);

   result = 1.0;
   for( i = 0; i < exponent; ++i )
   {
      result *= basis;
   }

   return result;
}

/**< Initialize probing objective coefficient for each variable with original objective. */
static
SCIP_RETCODE initProbingObjWithOrigObj(
   SCIP*                origscip,           /**< orig scip problem */
   SCIP_Bool            enableobj,          /**< returns if objective row was added to the lp */
   SCIP_Real            objfactor           /**< factor, the objective is multiplied with */
)
{
   SCIP_VAR** origvars;
   int norigvars;
   SCIP_VAR* origvar;

   SCIP_Real newobj;
   int i;

   assert(SCIPinProbing(origscip));

   origvars = SCIPgetVars(origscip);
   norigvars = SCIPgetNVars(origscip);

   /** loop over original variables */
   for( i = 0; i < norigvars; ++i )
   {
      /* get variable information */
      origvar = origvars[i];
      newobj = 0.0;

      /* if objective row is enabled consider also the original objective value */
      if( enableobj )
         newobj = objfactor * SCIPvarGetObj(origvar);

      SCIP_CALL( SCIPchgVarObjProbing(origscip, origvar, newobj) );
   }
   return SCIP_OKAY;
}

/**< Change probing objective coefficient for each variable by adding original objective
 *   to the probing objective.
 */
static
SCIP_RETCODE chgProbingObjAddingOrigObj(
   SCIP*                origscip,           /**< orig scip problem */
   SCIP_Real            objfactor,          /**< factor the additional part of the objective is multiplied with */
   SCIP_Real            objdivisor          /**< factor the additional part of the objective is divided with */
)
{
   SCIP_VAR** origvars;
   int norigvars;
   SCIP_VAR* origvar;

   SCIP_Real newobj;
   int i;

   assert(SCIPinProbing(origscip));

   origvars = SCIPgetVars(origscip);
   norigvars = SCIPgetNVars(origscip);

   /** loop over original variables */
   for( i = 0; i < norigvars; ++i )
   {
      /* get variable information */
      origvar = origvars[i];

      newobj = SCIPgetVarObjProbing(origscip, origvar) + (objfactor * SCIPvarGetObj(origvar))/ objdivisor ;

      SCIP_CALL( SCIPchgVarObjProbing(origscip, origvar, newobj) );
   }
   return SCIP_OKAY;
}

/**< Initialize probing objective coefficient for each variable depending on the current origsol.
 *
 *   If variable is at upper bound set objective to -1, if variable is at lower bound set obj to 1,
 *   else set obj to 0.
 *   Additionally, add original objective to the probing objective if this is enabled.
 */
static
SCIP_RETCODE initProbingObjUsingVarBounds(
   SCIP*                origscip,           /**< orig scip problem */
   SCIP_SEPADATA*       sepadata,           /**< separator specific data */
   SCIP_SOL*            origsol,            /**< orig solution */
   SCIP_Bool            enableobj,          /**< returns if objective row was added to the lp */
   SCIP_Real            objfactor           /**< factor the objective is multiplied with */
)
{
   SCIP_Bool enableposslack;
   int posslackexp;

   SCIP_VAR** origvars;
   int norigvars;
   SCIP_VAR* origvar;

   SCIP_Real lb;
   SCIP_Real ub;
   SCIP_Real solval;
   SCIP_Real newobj;
   SCIP_Real distance;

   int i;

   origvars = SCIPgetVars(origscip);
   norigvars = SCIPgetNVars(origscip);

   enableposslack = sepadata->enableposslack;
   posslackexp = sepadata->posslackexp;

   /** loop over original variables */
   for( i = 0; i < norigvars; ++i )
   {
      /* get variable information */
      origvar = origvars[i];
      lb = SCIPvarGetLbLocal(origvar);
      ub = SCIPvarGetUbLocal(origvar);
      solval = SCIPgetSolVal(origscip, origsol, origvar);

      assert(SCIPisFeasLE(origscip, solval, ub));
      assert(SCIPisFeasGE(origscip, solval, lb));

      /* if solution value of variable is at ub or lb initialize objective value of the variable
       * such that the difference to this bound is minimized
       */
      if( SCIPisFeasEQ(origscip, lb, ub) )
      {
         newobj = 0.0;
      }
      else if( SCIPisLT(origscip, ub, SCIPinfinity(origscip)) && SCIPisFeasLE(origscip, ub, solval) )
      {
         newobj = -1.0;
      }
      else if( SCIPisGT(origscip, lb, -SCIPinfinity(origscip)) && SCIPisFeasGE(origscip, lb, solval) )
      {
         newobj = 1.0;
      }
      else if( enableposslack )
      {
         /* compute distance from solution to variable bound */
         distance = MIN(solval - lb, ub - solval);

         assert(SCIPisFeasPositive(origscip, distance));

         /* check if distance is lower than 1 and compute factor */
         if( SCIPisLT(origscip, distance, 1.0) )
         {
            newobj = exponentiate(MAX(0.0, 1.0 - distance), posslackexp);

            /* check if algebraic sign has to be changed */
            if( SCIPisLT(origscip, distance, solval - lb) )
               newobj = -newobj;
         }
         else
         {
            newobj = 0.0;
         }
      }
      else
      {
         newobj = 0.0;
      }

      newobj = newobj * (int) SCIPgetObjsense(origscip);

      /* if objective row is enabled consider also the original objective value */
      if( enableobj )
         newobj = newobj + SCIPvarGetObj(origvar);

      SCIP_CALL( SCIPchgVarObjProbing(origscip, origvar, objfactor*newobj) );
   }

   return SCIP_OKAY;
}

/**< Change probing objective depending on the current origsol.
 *
 * Loop over all constraints lhs <= sum a_i*x_i <= rhs. If lhs == sum a_i*x_i^* add a_i to objective
 * of variable i and if rhs == sum a_i*x_i^* add -a_i to objective of variable i.
 */
static
SCIP_RETCODE chgProbingObjUsingRows(
   SCIP*                origscip,           /**< orig scip problem */
   SCIP_SEPADATA*       sepadata,           /**< separator data */
   SCIP_SOL*            origsol,            /**< orig solution */
   SCIP_Real            objfactor,          /**< factor the objective is multiplied with */
   SCIP_Real            objdivisor          /**< factor the objective is divided with */
)
{
   SCIP_Bool enableposslack;
   int posslackexp;

   SCIP_ROW** rows;
   int nrows;
   SCIP_ROW* row;
   SCIP_Real* vals;
   SCIP_VAR** vars;
   SCIP_COL** cols;
   int nvars;

   SCIP_Real lhs;
   SCIP_Real rhs;
   SCIP_Real* solvals;
   SCIP_Real activity;
   SCIP_Real factor;
   SCIP_Real objadd;
   SCIP_Real obj;
   SCIP_Real norm;
   SCIP_Real distance;

   int i;
   int j;

   rows = SCIPgetLPRows(origscip);
   nrows = SCIPgetNLPRows(origscip);

   enableposslack = sepadata->enableposslack;
   posslackexp = sepadata->posslackexp;

   assert(SCIPinProbing(origscip));

   SCIP_CALL( SCIPallocBufferArray(origscip, &solvals, SCIPgetNVars(origscip)) );
   SCIP_CALL( SCIPallocBufferArray(origscip, &vars, SCIPgetNVars(origscip)) );

   /** loop over constraint and check activity */
   for( i = 0; i < nrows; ++i )
   {
      row = rows[i];
      lhs = SCIProwGetLhs(row);
      rhs = SCIProwGetRhs(row);

      nvars = SCIProwGetNNonz(row);
      if( nvars == 0 || (sepadata->objrow != NULL && strcmp(SCIProwGetName(row),SCIProwGetName(sepadata->objrow)) == 0 ) )
         continue;

      /* get values, variables and solution values */
      vals = SCIProwGetVals(row);
      cols = SCIProwGetCols(row);
      for( j = 0; j < nvars; ++j )
      {
         vars[j] = SCIPcolGetVar(cols[j]);
      }

      activity = SCIPgetRowSolActivity(origscip, row, origsol);

      if( SCIPisFeasEQ(origscip, rhs, lhs) )
      {
         continue;
      }
      if( SCIPisLT(origscip, rhs, SCIPinfinity(origscip)) && SCIPisFeasLE(origscip, rhs, activity) )
      {
         factor = -1.0;
      }
      else if( SCIPisGT(origscip, lhs, -SCIPinfinity(origscip)) && SCIPisFeasGE(origscip, lhs, activity) )
      {
         factor = 1.0;
      }
      else if( enableposslack )
      {
         assert(!(SCIPisInfinity(origscip, rhs) && SCIPisInfinity(origscip, lhs)));
         assert(!(SCIPisInfinity(origscip, activity) && SCIPisInfinity(origscip, -activity)));

         /* compute distance from solution to row */
         if( SCIPisInfinity(origscip, rhs) && SCIPisGT(origscip, lhs, -SCIPinfinity(origscip)) )
            distance = activity - lhs;
         else if( SCIPisInfinity(origscip, lhs) && SCIPisLT(origscip, rhs, SCIPinfinity(origscip)) )
            distance = rhs - activity;
         else
            distance = MIN(activity - lhs, rhs - activity);

         assert(SCIPisFeasPositive(origscip, distance) || !SCIPisCutEfficacious(origscip, origsol, row));

         /* check if distance is lower than 1 and compute factor */
         if( SCIPisLT(origscip, distance, 1.0) )
         {
            factor = exponentiate(MAX(0.0, 1.0 - distance), posslackexp);

            /* check if algebraic sign has to be changed */
            if( SCIPisLT(origscip, distance, activity - lhs) )
               factor = -1.0*factor;
         }
         else
         {
            continue;
         }
      }
      else
      {
         continue;
      }

      norm = SCIProwGetNorm(row);

      /** loop over variables of the constraint and change objective */
      for( j = 0; j < nvars; ++j )
      {
         obj = SCIPgetVarObjProbing(origscip, vars[j]);
         objadd = (factor * vals[j]) / norm;

         objadd = objadd * (int) SCIPgetObjsense(origscip);

         SCIP_CALL( SCIPchgVarObjProbing(origscip, vars[j], obj + (objfactor * objadd) / objdivisor) );
      }
   }

   SCIPfreeBufferArray(origscip, &solvals);
   SCIPfreeBufferArray(origscip, &vars);

   return SCIP_OKAY;
}

#ifdef GSL
/**< Get matrix (including nrows and ncols) of rows that are satisfied with equality by sol */
static
SCIP_RETCODE getEqualityMatrixGsl(
   SCIP*                scip,               /**< SCIP data structure */
   SCIP_SOL*            sol,                /**< solution */
   gsl_matrix**         matrix,             /**< pointer to store equality matrix */
   int*                 nrows,              /**< pointer to store number of rows */
   int*                 ncols,              /**< pointer to store number of columns */
   int*                 prerank             /**< pointer to store preprocessed rank */
)
{
   int* var2col;
   int* delvars;

   int nvar2col;
   int ndelvars;

   SCIP_ROW** lprows;
   int nlprows;

   SCIP_COL** lpcols;
   int nlpcols;

   int i;
   int j;

   *ncols = SCIPgetNLPCols(scip);
   nlprows = SCIPgetNLPRows(scip);
   lprows = SCIPgetLPRows(scip);
   nlpcols = SCIPgetNLPCols(scip);
   lpcols = SCIPgetLPCols(scip);

   *nrows = 0;

   ndelvars = 0;
   nvar2col = 0;

   SCIP_CALL( SCIPallocBufferArray(scip, &var2col, nlpcols) );
   SCIP_CALL( SCIPallocBufferArray(scip, &delvars, nlpcols) );

   /* loop over lp cols and check if it is at one of its bounds */
   for( i = 0; i < nlpcols; ++i )
   {
      SCIP_COL* lpcol;
      SCIP_VAR* lpvar;

      lpcol = lpcols[i];

      lpvar = SCIPcolGetVar(lpcol);

      if( SCIPisEQ(scip, SCIPgetSolVal(scip, sol, lpvar), SCIPcolGetUb(lpcol) )
         || SCIPisEQ(scip, SCIPgetSolVal(scip, sol, lpvar), SCIPcolGetLb(lpcol)) )
      {
         int ind;

         ind = SCIPcolGetIndex(lpcol);

         delvars[ndelvars] = ind;

         ++ndelvars;

         var2col[ind] = -1;
      }
      else
      {
         int ind;

         ind = SCIPcolGetIndex(lpcol);

         var2col[ind] = nvar2col;

         ++nvar2col;
      }
   }

   SCIPsortInt(delvars, ndelvars);

   *matrix = gsl_matrix_calloc(nlprows, nvar2col);

   *ncols = nvar2col;

   /* loop over lp rows and check if solution feasibility is equal to zero */
   for( i = 0; i < nlprows; ++i )
   {
      SCIP_ROW* lprow;

      lprow = lprows[i];

      /* if solution feasiblity is equal to zero, add row to matrix */
      if( SCIPisEQ(scip, SCIPgetRowSolFeasibility(scip, lprow, sol), 0.0) )
      {
         SCIP_COL** cols;
         SCIP_Real* vals;
         int nnonz;

         cols = SCIProwGetCols(lprow);
         vals = SCIProwGetVals(lprow);
         nnonz = SCIProwGetNNonz(lprow);

         /* get nonzero coefficients of row */
         for( j = 0; j < nnonz; ++j )
         {
            int ind;
            int pos;

            ind = SCIPcolGetIndex(cols[j]);
            assert(ind >= 0 && ind < nlpcols);

            if( !SCIPsortedvecFindInt(delvars, ind, ndelvars, &pos) )
            {
               gsl_matrix_set(*matrix, *nrows, var2col[ind], vals[j]);
            }
         }
         ++(*nrows);
      }
   }
   *nrows = nlprows;
   *prerank = ndelvars;

   SCIPfreeBufferArray(scip, &delvars);
   SCIPfreeBufferArray(scip, &var2col);

   return SCIP_OKAY;
}

/**< get the rank of a given matrix */
static
SCIP_RETCODE getRank(
   SCIP*                scip,
   gsl_matrix*          matrix,
   int                  nrows,
   int                  ncols,
   int*                 rank
)
{
   gsl_matrix* matrixq;
   gsl_matrix* matrixr;

   gsl_vector* tau;
   gsl_vector* norm;
   gsl_permutation* permutation;

   int ranktmp;
   int signum;

   int i;

   matrixq = gsl_matrix_alloc(nrows, nrows);
   matrixr = gsl_matrix_alloc(nrows, ncols);

   norm = gsl_vector_alloc(ncols);
   tau = gsl_vector_alloc(MIN(nrows, ncols));

   permutation = gsl_permutation_alloc(ncols);

   gsl_linalg_QRPT_decomp(matrix, tau, permutation, &signum, norm);

   gsl_linalg_QR_unpack(matrix, tau, matrixq, matrixr);

   ranktmp = 0;

   for( i = 0; i < MIN(nrows, ncols); ++i )
   {
      SCIP_Real val;

      val = gsl_matrix_get(matrixr, i, i);

      if( SCIPisZero(scip, val) )
      {
         break;
      }
      ++(ranktmp);
   }

   *rank = ranktmp;

   gsl_matrix_free(matrixq);
   gsl_matrix_free(matrixr);

   gsl_vector_free(tau);
   gsl_vector_free(norm);

   gsl_permutation_free(permutation);

   return SCIP_OKAY;
}

/**< Get rank (number of linear independent rows) of rows that are satisfied
 *   with equality by solution sol */
static
SCIP_RETCODE getEqualityRankGsl(
   SCIP*                scip,               /**< SCIP data structure */
   SCIP_SOL*            sol,                /**< solution */
   int*                 equalityrank        /**< pointer to store rank of rows with equality */
   )
{
   gsl_matrix* matrix;
   int nrows;
   int ncols;

   int prerank;
   int rowrank;

   SCIP_CALL( getEqualityMatrixGsl(scip, sol, &matrix, &nrows, &ncols, &prerank) );

   SCIP_CALL( getRank(scip, matrix, nrows, ncols, &rowrank) );

   gsl_matrix_free(matrix);

   *equalityrank = rowrank + prerank;

   return SCIP_OKAY;
}
#endif

/** add cuts which are due to the latest objective function of the pricing problems
 *  (reduced cost non-negative) */
static
SCIP_RETCODE addPPObjConss(
   SCIP*                scip,               /**< SCIP data structure */
   SCIP_SEPA*           sepa,               /**< separator basis */
   int                  ppnumber,           /**< number of pricing problem */
   SCIP_Real            dualsolconv,        /**< dual solution corresponding to convexity constraint */
   SCIP_Bool            newcuts,            /**< add cut to newcuts in sepadata? (otherwise add it just to the cutpool) */
   SCIP_Bool            probing             /**< add cut to probing LP? */
)
{
   SCIP_SEPADATA* sepadata;

   SCIP* pricingscip;

   SCIP_VAR** pricingvars;
   SCIP_VAR* var;

   int npricingvars;
   int nvars;

   char name[SCIP_MAXSTRLEN];

   int j;
   int k;

   SCIP_OBJSENSE objsense;

   SCIP_Real lhs;
   SCIP_Real rhs;

   sepadata = SCIPsepaGetData(sepa);

   nvars = 0;
   pricingscip = GCGgetPricingprob(scip, ppnumber);
   pricingvars = SCIPgetOrigVars(pricingscip);
   npricingvars = SCIPgetNOrigVars(pricingscip);

   if( !GCGisPricingprobRelevant(scip, ppnumber) || pricingscip == NULL )
      return SCIP_OKAY;

   objsense = SCIPgetObjsense(pricingscip);

   if( objsense == SCIP_OBJSENSE_MINIMIZE )
   {
      lhs = dualsolconv;
      rhs = SCIPinfinity(scip);
   }
   else
   {
      rhs = dualsolconv;
      lhs = -SCIPinfinity(scip);
   }

   for( k = 0; k < GCGgetNIdenticalBlocks(scip, ppnumber); ++k )
   {
      SCIP_ROW* origcut;

      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "newconstraint_%d_%d_%d", SCIPsepaGetNCalls(sepa), ppnumber, k);

      SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &origcut, name, lhs, rhs, FALSE, FALSE, TRUE) );

      nvars = 0;

      for( j = 0; j < npricingvars ; ++j )
      {
         assert(GCGvarIsPricing(pricingvars[j]));

         if( !SCIPisEQ(scip, SCIPvarGetObj(pricingvars[j]), 0.0) )
         {
            var = GCGpricingVarGetOrigvars(pricingvars[j])[k];
            assert(var != NULL);
            SCIP_CALL( SCIPaddVarToRow(scip, origcut, var, SCIPvarGetObj(pricingvars[j])) );
            ++nvars;
         }
      }

      if( nvars > 0 )
      {
         if( newcuts )
         {
            SCIP_CALL( ensureSizeNewCuts(scip, sepadata, sepadata->nnewcuts + 1) );

            sepadata->newcuts[sepadata->nnewcuts] = origcut;
            SCIP_CALL( SCIPcaptureRow(scip, sepadata->newcuts[sepadata->nnewcuts]) );
            ++(sepadata->nnewcuts);

            SCIPdebugMessage("cut added to new cuts in relaxdata\n");
         }
         else
         {
            SCIP_CALL( SCIPaddPoolCut(scip, origcut) );
            SCIPdebugMessage("cut added to orig cut pool\n");
         }

         if( probing )
         {
            SCIP_CALL( SCIPaddRowProbing(scip, origcut) );
            SCIPdebugMessage("cut added to probing\n");
         }

      }
      SCIP_CALL( SCIPreleaseRow(scip, &origcut) );
   }

   return SCIP_OKAY;
}
/*
 * Callback methods of separator
 */

/** copy method for separator plugins (called when SCIP copies plugins) */
#if 0
static
SCIP_DECL_SEPACOPY(sepaCopyBasis)
{  /*lint --e{715}*/
   SCIPerrorMessage("method of basis separator not implemented yet\n");
   SCIPABORT(); /*lint --e{527}*/

   return SCIP_OKAY;
}
#else
#define sepaCopyBasis NULL
#endif

/** destructor of separator to free user data (called when SCIP is exiting) */
static
SCIP_DECL_SEPAFREE(sepaFreeBasis)
{  /*lint --e{715}*/
   SCIP_SEPADATA* sepadata;

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   SCIPfreeMemory(scip, &sepadata);

   return SCIP_OKAY;
}

/** initialization method of separator (called after problem was transformed) */
static
SCIP_DECL_SEPAINIT(sepaInitBasis)
{  /*lint --e{715}*/
   SCIP*   origscip;
   SCIP_SEPADATA* sepadata;

   SCIP_VAR** origvars;
   int norigvars;

   char name[SCIP_MAXSTRLEN];

   SCIP_Real obj;
   int i;

   SCIP_Bool enable;
   SCIP_Bool enableobj;

   assert(scip != NULL);

   origscip = GCGmasterGetOrigprob(scip);
   assert(origscip != NULL);

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   origvars = SCIPgetVars(origscip);
   norigvars = SCIPgetNVars(origscip);

   SCIPdebugMessage("sepaInitBasis\n");

   enable = sepadata->enable;
   enableobj = sepadata->enableobj;

   sepadata->maxcuts = STARTMAXCUTS;
   sepadata->norigcuts = 0;
   sepadata->maxnewcuts = 0;
   sepadata->nnewcuts = 0;
   sepadata->objrow = NULL;

   /* if separator is disabled do nothing */
   if( !enable )
   {
      return SCIP_OKAY;
   }

   SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->origcuts), STARTMAXCUTS) ); /*lint !e506*/
   SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->mastercuts), STARTMAXCUTS) ); /*lint !e506*/
   SCIP_CALL( SCIPallocMemoryArray(scip, &(sepadata->newcuts), STARTMAXCUTS) ); /*lint !e506*/

   /* if objective row is enabled create row with objective coefficients */
   if( enableobj )
   {
      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "objrow");
      SCIP_CALL( SCIPcreateEmptyRowUnspec(origscip, &(sepadata->objrow), name, -SCIPinfinity(origscip), SCIPinfinity(origscip), TRUE, FALSE, TRUE) );

      for( i = 0; i < norigvars; ++i )
      {
         obj = SCIPvarGetObj(origvars[i]);
         SCIP_CALL( SCIPaddVarToRow(origscip, sepadata->objrow, origvars[i], obj) );
      }
   }

   return SCIP_OKAY;
}

/** deinitialization method of separator (called before transformed problem is freed) */
static
SCIP_DECL_SEPAEXIT(sepaExitBasis)
{  /*lint --e{715}*/
   SCIP* origscip;
   SCIP_SEPADATA* sepadata;
   SCIP_Bool enableobj;

   int i;

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);
   enableobj = sepadata->enableobj;
   assert(sepadata->nmastercuts == sepadata->norigcuts);

   origscip = GCGmasterGetOrigprob(scip);
   assert(origscip != NULL);

   for( i = 0; i < sepadata->norigcuts; i++ )
   {
      SCIP_CALL( SCIPreleaseRow(origscip, &(sepadata->origcuts[i])) );
   }

   for( i = 0; i < sepadata->nnewcuts; ++i )
   {
      if( sepadata->newcuts[i] != NULL )
         SCIP_CALL( SCIPreleaseRow(origscip, &(sepadata->newcuts[i])) );
   }

   if( enableobj )
      SCIP_CALL( SCIPreleaseRow(origscip, &(sepadata->objrow)) );

   SCIPfreeMemoryArrayNull(scip, &(sepadata->origcuts));
   SCIPfreeMemoryArrayNull(scip, &(sepadata->mastercuts));
   SCIPfreeMemoryArrayNull(scip, &(sepadata->newcuts));

   return SCIP_OKAY;
}

/** solving process initialization method of separator (called when branch and bound process is about to begin) */
static
SCIP_DECL_SEPAINITSOL(sepaInitsolBasis)
{  /*lint --e{715}*/
   SCIP_SEPADATA* sepadata;

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   sepadata->nmastercuts = 0;

   return SCIP_OKAY;
}

/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
static
SCIP_DECL_SEPAEXITSOL(sepaExitsolBasis)
{  /*lint --e{715}*/
   SCIP_SEPADATA* sepadata;
   int i;

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);
   assert(sepadata->nmastercuts == sepadata->norigcuts);

   assert(GCGmasterGetOrigprob(scip) != NULL);

   for( i = 0; i < sepadata->nmastercuts; i++ )
   {
      SCIP_CALL( SCIPreleaseRow(scip, &(sepadata->mastercuts[i])) );
   }

   return SCIP_OKAY;
}

/**< Initialize objective due to generation of convex combination */
static
SCIP_RETCODE initGenconv(
   SCIP*                origscip,           /**< original SCIP data structure */
   SCIP_SEPADATA*       sepadata,           /**< separator data structure */
   SCIP_SOL*            origsol,            /**< current original solution */
   int                  nbasis,             /**< rank of constraint matrix */
   SCIP_Real*           convex              /**< pointer to store convex combination coefficient */
)
{  /*lint --e{715}*/
#ifdef GSL
   int rank;

   SCIP_CALL( getEqualityRankGsl(origscip, origsol, &rank) );

   *convex = 1.0* rank/nbasis;

   SCIPdebugMessage("use generic coefficient %d/%d = %f\n", rank, nbasis, *convex);

#else
   SCIPwarningMessage(origscip, "Gnu Scientific Library is not enabled! \n"
      "either set sepa/basis/genobjconvex = FALSE sepa/basis/posslackexpgen = FALSE \n"
      "or compile with GSL=true and include Gnu Scientific Library\n");
   *convex = sepadata->objconvex;
#endif

   return SCIP_OKAY;
}

/**< Initialize objective due to generation of convex combination */
static
SCIP_RETCODE initConvObj(
   SCIP*                origscip,           /**< original SCIP data structure */
   SCIP_SEPADATA*       sepadata,           /**< separator data structure */
   SCIP_SOL*            origsol,            /**< current original solution */
   SCIP_Real            convex,             /**< convex coefficient to initialize objective */
   SCIP_Bool            genericconv         /**< was convex coefficient calculated generically? */
)
{
   SCIP_Real objnormnull;
   SCIP_Real objnormcurrent;

   objnormnull = 1.0;
   objnormcurrent = 1.0;

   if( SCIPisEQ(origscip, convex, 0.0) )
   {
      SCIP_CALL( initProbingObjWithOrigObj(origscip, TRUE, 1.0) );
   }
   else if( SCIPisLT(origscip, convex, 1.0) )
   {
      SCIP_CALL( initProbingObjWithOrigObj(origscip, TRUE, 1.0) );
      objnormnull = SCIPgetObjNorm(origscip);

      SCIP_CALL( initProbingObjUsingVarBounds(origscip, sepadata, origsol, FALSE, convex) );
      SCIP_CALL( chgProbingObjUsingRows(origscip, sepadata, origsol, convex, 1.0) );

      objnormcurrent = SCIPgetObjNorm(origscip)/(convex);

      if( SCIPisEQ(origscip, objnormcurrent, 0.0) )
         SCIP_CALL( initProbingObjWithOrigObj(origscip, TRUE, 1.0) );
      else if( SCIPisGT(origscip, objnormnull, 0.0) )
         SCIP_CALL( chgProbingObjAddingOrigObj(origscip, (1.0 - convex) * objnormcurrent, objnormnull) );
   }
   else if( SCIPisEQ(origscip, convex, 1.0) )
   {
      SCIP_CALL( initProbingObjUsingVarBounds(origscip, sepadata, origsol, !genericconv && sepadata->enableobj, 1.0) );
      SCIP_CALL( chgProbingObjUsingRows(origscip, sepadata, origsol, 1.0, 1.0) );
   }

   return SCIP_OKAY;
}

/** LP solution separation method of separator */
static
SCIP_DECL_SEPAEXECLP(sepaExeclpBasis)
{  /*lint --e{715}*/

   SCIP* origscip;
   SCIP_SEPADATA* sepadata;

   SCIP_SEPA** sepas;
   int nsepas;

   SCIP_ROW** cuts;
   SCIP_ROW* mastercut;
   SCIP_ROW* origcut;
   SCIP_COL** cols;
   SCIP_VAR** roworigvars;
   SCIP_VAR** mastervars;
   SCIP_Real* mastervals;
   int ncols;
   int ncuts;
   SCIP_Real* vals;
   int nmastervars;

   SCIP_RESULT resultdummy;
   SCIP_OBJSENSE objsense;
   SCIP_SOL* origsol;
   SCIP_Bool lperror;
   SCIP_Bool delayed;
   SCIP_Bool cutoff;
   SCIP_Bool infeasible;
   SCIP_Real obj;

   SCIP_Bool enable;
   SCIP_Bool enableobj;
   SCIP_Bool enableobjround;
   SCIP_Bool enableppobjconss;

   char name[SCIP_MAXSTRLEN];

   int i;
   int j;
   int iteration;
   int nbasis;
   int nlprowsstart;
   int nlprows;
   SCIP_ROW** lprows;

   assert(scip != NULL);
   assert(result != NULL);

   origscip = GCGmasterGetOrigprob(scip);
   assert(origscip != NULL);

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   SCIPdebugMessage("calling sepaExeclpBasis\n");

   *result = SCIP_DIDNOTFIND;

   enable = sepadata->enable;
   enableobj = sepadata->enableobj;
   enableobjround = sepadata->enableobjround;
   enableppobjconss = sepadata->enableppobjconss;

   /* if separator is disabled do nothing */
   if( !enable )
   {
      SCIPdebugMessage("separator is not enabled\n");
      *result = SCIP_DIDNOTRUN;
      return SCIP_OKAY;
   }

   /* ensure master LP is solved to optimality */
   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
   {
      SCIPdebugMessage("master LP not solved to optimality, do no separation!\n");
      *result = SCIP_DIDNOTRUN;
      return SCIP_OKAY;
   }

   if( GCGgetNRelPricingprobs(origscip) < GCGgetNPricingprobs(origscip) )
   {
      SCIPdebugMessage("aggregated pricing problems, do no separation!\n");
      *result = SCIP_DIDNOTRUN;
      return SCIP_OKAY;
   }

   if( GCGrelaxIsOrigSolFeasible(origscip) )
   {
      SCIPdebugMessage("Current solution is feasible, no separation necessary!\n");
      *result = SCIP_DIDNOTRUN;
      return SCIP_OKAY;
   }

   /* get current original solution */
   origsol = GCGrelaxGetCurrentOrigSol(origscip);

   /* get obj and objsense */
   objsense = SCIPgetObjsense(origscip);
   obj = SCIPgetSolOrigObj(origscip, origsol);

   /** get number of linearly independent rows needed for basis */
   nbasis = SCIPgetNLPCols(origscip);

   *result = SCIP_DIDNOTFIND;

   /* init iteration counter */
   iteration = 0;

   /* set parameter setting for separation */
   SCIP_CALL( SCIPsetSeparating(origscip, (SCIP_PARAMSETTING) sepadata->separationsetting, TRUE) );

   /* start diving */
   SCIP_CALL( SCIPstartProbing(origscip) );

   SCIP_CALL( SCIPnewProbingNode(origscip) );

   SCIP_CALL( SCIPconstructLP(origscip, &cutoff) );

   /** add origcuts to probing lp */
   for( i = 0; i < GCGsepaGetNCuts(scip); ++i )
   {
      if( SCIProwGetLPPos(GCGsepaGetOrigcuts(scip)[i]) == -1 )
         SCIP_CALL( SCIPaddRowProbing(origscip, GCGsepaGetOrigcuts(scip)[i]) );
   }

   /** add new cuts which did not cut off master sol to probing lp */
   for( i = 0; i < sepadata->nnewcuts; ++i )
   {
      if( SCIProwGetLPPos(sepadata->newcuts[i]) == -1 )
         SCIP_CALL( SCIPaddRowProbing(origscip, sepadata->newcuts[i]) );
   }

   /* store number of lp rows in the beginning */
   nlprowsstart = SCIPgetNLPRows(origscip);

   /* while the counter is smaller than the number of allowed iterations,
    * try to separate origsol via probing lp sol */
   /* TODO: while z*(T) = 0 like Range suggests? But then we have to adjust which cuts are added */
   while( iteration < sepadata->iterations )
   {
      SCIPdebugMessage("iteration %d of at most %d iterations\n", iteration + 1, sepadata->iterations);

      SCIP_CALL( SCIPapplyCutsProbing(origscip, &cutoff) );

      /* add new constraints if this is enabled  */
      if( enableppobjconss && iteration == 0 )
      {
         SCIP_Real* dualsolconv;

         SCIPdebugMessage("add reduced cost cut for relevant pricing problems\n");

         SCIP_CALL( SCIPallocMemoryArray(scip, &dualsolconv, GCGgetNPricingprobs(origscip)) );
         SCIP_CALL( GCGsetPricingObjs(scip, dualsolconv) );

         for( i = 0; i < GCGgetNPricingprobs(origscip); ++i )
         {
            SCIP_CALL( addPPObjConss(origscip, sepa, i, dualsolconv[i], FALSE, TRUE) );
         }

         SCIPfreeMemoryArray(scip, &dualsolconv);
      }

      /* init objective */
      if( sepadata->chgobj && (iteration == 0 || sepadata->chgobjallways) )
      {
         SCIPdebugMessage("initialize objective function\n");
         if( sepadata->genobjconvex )
         {
            SCIP_Real genconvex;

            SCIP_CALL( initGenconv(origscip, sepadata, origsol, nbasis, &genconvex) );

            SCIP_CALL( initConvObj(origscip, sepadata, origsol, genconvex, TRUE) );
         }
         else
         {
            SCIPdebugMessage("use given coefficient %g\n", sepadata->objconvex);

            if( sepadata->enableposslack && sepadata->posslackexpgen )
            {
               SCIP_Real genconvex;
               SCIP_Real factor;

               factor = sepadata->posslackexpgenfactor;

               SCIP_CALL( initGenconv(origscip, sepadata, origsol, nbasis, &genconvex) );

               sepadata->posslackexp = (int) (SCIPceil(origscip, factor/(1.0 - genconvex)) + 0.5);

               SCIPdebugMessage("exponent = %d\n", sepadata->posslackexp);

            }
            SCIP_CALL( initConvObj(origscip, sepadata, origsol, sepadata->objconvex, FALSE) );
         }
      }

      /* update rhs/lhs of objective constraint and add it to probing LP, if it exists (only in first iteration) */
      if( enableobj && iteration == 0 )
      {
         SCIPdebugMessage("initialize original objective cut\n");

         /* round rhs/lhs of objective constraint, if it exists, obj is integral and this is enabled */
         if( SCIPisObjIntegral(origscip) && enableobjround )
         {
            if( objsense == SCIP_OBJSENSE_MAXIMIZE )
            {
               SCIPdebugMessage("round rhs down\n");
               obj = SCIPfloor(origscip, obj);
            }
            else
            {
               SCIPdebugMessage("round lhs up\n");
               obj = SCIPceil(origscip, obj);
            }
         }

         /* update rhs/lhs of objective constraint */
         if( objsense == SCIP_OBJSENSE_MAXIMIZE )
         {
            SCIP_CALL( SCIPchgRowRhs(origscip, sepadata->objrow, obj) );
            SCIP_CALL( SCIPchgRowLhs(origscip, sepadata->objrow, -1.0*SCIPinfinity(origscip)) );
         }
         else
         {
            SCIP_CALL( SCIPchgRowLhs(origscip, sepadata->objrow, obj) );
            SCIP_CALL( SCIPchgRowRhs(origscip, sepadata->objrow, SCIPinfinity(origscip)) );
         }
         SCIPdebugMessage("add original objective cut to probing LP\n");

         /** add row to probing lp */
         SCIP_CALL( SCIPaddRowProbing(origscip, sepadata->objrow) );
      }

      SCIPdebugMessage("solve probing LP\n");

      /* solve probing lp */
      SCIP_CALL( SCIPsolveProbingLP(origscip, -1, &lperror, &cutoff) );

      assert(!lperror);

      /* get separators of origscip */
      sepas = SCIPgetSepas(origscip);
      nsepas = SCIPgetNSepas(origscip);

      SCIPdebugMessage("set parameters of separators\n");

      /* loop over sepas and enable/disable sepa */
      for( i = 0; i < nsepas; ++i )
      {
         const char* sepaname;
         char paramname[SCIP_MAXSTRLEN];

         sepaname = SCIPsepaGetName(sepas[i]);

         (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "separating/%s/freq", sepaname);

         /* disable intobj, closecuts, rapidlearning and cgmip separator*/
         if( strcmp(sepaname, "intobj") == 0 || strcmp(sepaname, "closecuts") == 0
            || strcmp(sepaname, "rapidlearning") == 0
            || (strcmp(sepaname, "cgmip") == 0))
         {
            SCIP_CALL( SCIPsetIntParam(origscip, paramname, -1) );
         }
         else
         {
            SCIP_CALL( SCIPsetIntParam(origscip, paramname, 0) );
         }
      }

      SCIPdebugMessage("separate current LP solution\n");

      /** separate current probing lp sol of origscip */
      SCIP_CALL( SCIPseparateSol(origscip, NULL, TRUE, FALSE, TRUE, &delayed, &cutoff) );

      if( delayed && !cutoff )
      {
         SCIPdebugMessage("call delayed separators\n");

         SCIP_CALL( SCIPseparateSol(origscip, NULL, TRUE, TRUE, TRUE, &delayed, &cutoff) );
      }

      /* if cut off is detected set result pointer and return SCIP_OKAY */
      if( cutoff )
      {
         *result = SCIP_CUTOFF;
         SCIP_CALL( SCIPendProbing(origscip) );

         /* disable separating again */
         SCIP_CALL( SCIPsetSeparating(origscip, SCIP_PARAMSETTING_OFF, TRUE) );

         return SCIP_OKAY;
      }

      SCIPdebugMessage("separate current LP solution and current original solution in cutpool\n");

      /* separate cuts in cutpool */
      SCIP_CALL( SCIPseparateSolCutpool(origscip, SCIPgetGlobalCutpool(origscip), NULL, &resultdummy) );
      SCIP_CALL( SCIPseparateSolCutpool(origscip, SCIPgetDelayedGlobalCutpool(origscip), NULL, &resultdummy) );

      /* separate cuts in cutpool */
      SCIP_CALL( SCIPseparateSolCutpool(origscip, SCIPgetGlobalCutpool(origscip), origsol, &resultdummy) );
      SCIP_CALL( SCIPseparateSolCutpool(origscip, SCIPgetDelayedGlobalCutpool(origscip), origsol, &resultdummy) );

      assert(sepadata->norigcuts == sepadata->nmastercuts);

      SCIPdebugMessage("%d cuts are in the original sepastore!\n", SCIPgetNCuts(origscip));

      /* get separated cuts */
      cuts = SCIPgetCuts(origscip);
      ncuts = SCIPgetNCuts(origscip);

      SCIP_CALL( ensureSizeCuts(scip, sepadata, sepadata->norigcuts + ncuts) );

      mastervars = SCIPgetVars(scip);
      nmastervars = SCIPgetNVars(scip);
      SCIP_CALL( SCIPallocBufferArray(scip, &mastervals, nmastervars) );

      /** loop over cuts and transform cut to master problem (and safe cuts) if it seperates origsol */
      for( i = 0; i < ncuts; i++ )
      {
         SCIP_Bool colvarused;

         colvarused = FALSE;
         origcut = cuts[i];

         /* get columns and vals of the cut */
         ncols = SCIProwGetNNonz(origcut);
         cols = SCIProwGetCols(origcut);
         vals = SCIProwGetVals(origcut);

         /* get the variables corresponding to the columns in the cut */
         SCIP_CALL( SCIPallocBufferArray(scip, &roworigvars, ncols) );
         for( j = 0; j < ncols; j++ )
         {
            roworigvars[j] = SCIPcolGetVar(cols[j]);
            assert(roworigvars[j] != NULL);
            if( !GCGvarIsOriginal(roworigvars[j]) )
            {
               colvarused = TRUE;
               break;
            }
         }

         if( colvarused )
         {
            SCIPwarningMessage(origscip, "colvar used in original cut %s\n", SCIProwGetName(origcut));
            SCIPfreeBufferArray(scip, &roworigvars);
            continue;
         }

         if( !SCIPisCutEfficacious(origscip, origsol, origcut) )
         {
            if( !SCIProwIsLocal(origcut) )
               SCIP_CALL( SCIPaddPoolCut(origscip, origcut) );

            SCIPfreeBufferArray(scip, &roworigvars);

            continue;
         }

         /* add the cut to the original cut storage */
         sepadata->origcuts[sepadata->norigcuts] = origcut;
         SCIP_CALL( SCIPcaptureRow(origscip, sepadata->origcuts[sepadata->norigcuts]) );
         sepadata->norigcuts++;

         /* create new cut in the master problem */
         (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "mc_basis_%s", SCIProwGetName(origcut));
         SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &mastercut, sepa, name,
               ( SCIPisInfinity(scip, -SCIProwGetLhs(origcut)) ?
                  SCIProwGetLhs(origcut) : SCIProwGetLhs(origcut) - SCIProwGetConstant(origcut)),
               ( SCIPisInfinity(scip, SCIProwGetRhs(origcut)) ?
                  SCIProwGetRhs(origcut) : SCIProwGetRhs(origcut) - SCIProwGetConstant(origcut)),
                  SCIProwIsLocal(origcut), TRUE, FALSE) );

         /* transform the original variables to master variables and add them to the cut */
         GCGtransformOrigvalsToMastervals(origscip, roworigvars, vals, ncols, mastervars, mastervals, nmastervars);
         SCIP_CALL( SCIPaddVarsToRow(scip, mastercut, nmastervars, mastervars, mastervals) );

         /* add the cut to the master problem and to the master cut storage */
         SCIP_CALL( SCIPaddRow(scip, mastercut, sepadata->forcecuts, &infeasible) );
         sepadata->mastercuts[sepadata->nmastercuts] = mastercut;
         SCIP_CALL( SCIPcaptureRow(scip, sepadata->mastercuts[sepadata->nmastercuts]) );
         sepadata->nmastercuts++;
         SCIP_CALL( GCGsepaAddMastercuts(scip, origcut, mastercut) );

         SCIP_CALL( SCIPreleaseRow(scip, &mastercut) );
         SCIPfreeBufferArray(scip, &roworigvars);
      }

      if( SCIPgetNCuts(scip) >= sepadata->mincuts )
      {
         *result = SCIP_SEPARATED;

         iteration = sepadata->iterations;
      }
      else if( SCIPgetNCuts(origscip) == 0 )
      {
         iteration = sepadata->iterations;
      }
      else
      {
         ++iteration;
      }

      SCIPdebugMessage("%d cuts are in the master sepastore!\n", SCIPgetNCuts(scip));

      SCIPfreeBufferArray(scip, &mastervals);

      assert(sepadata->norigcuts == sepadata->nmastercuts );
   }

   SCIP_CALL( SCIPclearCuts(origscip) );

   lprows = SCIPgetLPRows(origscip);
   nlprows = SCIPgetNLPRows(origscip);

   assert(nlprowsstart <= nlprows);

   SCIP_CALL( ensureSizeNewCuts(scip, sepadata, sepadata->nnewcuts + nlprows - nlprowsstart) );

   for( i = nlprowsstart; i < nlprows; ++i )
   {
      if( SCIProwGetOrigintype(lprows[i]) == SCIP_ROWORIGINTYPE_SEPA )
	   {
         sepadata->newcuts[sepadata->nnewcuts] = lprows[i];
	      SCIP_CALL( SCIPcaptureRow(origscip, sepadata->newcuts[sepadata->nnewcuts]) );
	      ++(sepadata->nnewcuts);
	   }
   }

   /* end diving */
   SCIP_CALL( SCIPendProbing(origscip) );

   if( SCIPgetNCuts(scip) > 0 )
   {
      *result = SCIP_SEPARATED;
   }

   /* disable separating again */
   SCIP_CALL( SCIPsetSeparating(origscip, SCIP_PARAMSETTING_OFF, TRUE) );

   SCIPdebugMessage("exiting sepaExeclpBasis\n");

   return SCIP_OKAY;
}

/** arbitrary primal solution separation method of separator */
#if 0
static
SCIP_DECL_SEPAEXECSOL(sepaExecsolBasis)
{  /*lint --e{715}*/
   SCIPerrorMessage("method of basis separator not implemented yet\n");
   SCIPABORT(); /*lint --e{527}*/

   return SCIP_OKAY;
}
#else
#define sepaExecsolBasis NULL
#endif

/*
 * separator specific interface methods
 */

/** creates the basis separator and includes it in SCIP */
SCIP_RETCODE SCIPincludeSepaBasis(
   SCIP*                 scip                /**< SCIP data structure */
   )
{
   SCIP_SEPADATA* sepadata;

   /* create master separator data */
   SCIP_CALL( SCIPallocMemory(scip, &sepadata) );

   sepadata->mastercuts = NULL;
   sepadata->origcuts = NULL;
   sepadata->norigcuts = 0;
   sepadata->nmastercuts = 0;
   sepadata->maxcuts = 0;
   sepadata->newcuts = NULL;
   sepadata->nnewcuts = 0;
   sepadata->maxnewcuts = 0;
   sepadata->objrow = NULL;

   /* include separator */
   SCIP_CALL( SCIPincludeSepa(scip, SEPA_NAME, SEPA_DESC, SEPA_PRIORITY, SEPA_FREQ, SEPA_MAXBOUNDDIST,
         SEPA_USESSUBSCIP, SEPA_DELAY,
         sepaCopyBasis, sepaFreeBasis, sepaInitBasis, sepaExitBasis, sepaInitsolBasis, sepaExitsolBasis, sepaExeclpBasis, sepaExecsolBasis,
         sepadata) );

   /* add basis separator parameters */
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/enable", "is basis separator enabled?",
         &(sepadata->enable), FALSE, TRUE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/enableobj", "is objective constraint of separator enabled?",
         &(sepadata->enableobj), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/enableobjround", "round obj rhs/lhs of obj constraint if obj is int?",
         &(sepadata->enableobjround), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/enableppcuts", "add cuts generated during pricing to newconss array?",
         &(sepadata->enableppcuts), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/enableppobjconss", "is objective constraint for redcost of each pp of "
      "separator enabled?", &(sepadata->enableppobjconss), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/enableppobjcg", "is objective constraint for redcost of each pp during "
      "pricing of separator enabled?", &(sepadata->enableppobjcg), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/genobjconvex", "generated obj convex dynamically",
         &(sepadata->genobjconvex), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/enableposslack", "should positive slack influence the probing objective "
      "function?", &(sepadata->enableposslack), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddIntParam(GCGmasterGetOrigprob(scip), "sepa/basis/posslackexp", "exponent of positive slack usage",
         &(sepadata->posslackexp), FALSE, 1, 1, INT_MAX, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/posslackexpgen", "automatically generated exponent?",
            &(sepadata->posslackexpgen), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddRealParam(GCGmasterGetOrigprob(scip), "sepa/basis/posslackexpgenfactor", "factor for automatically generated exponent",
            &(sepadata->posslackexpgenfactor), FALSE, 0.1, SCIPepsilon(GCGmasterGetOrigprob(scip)),
            SCIPinfinity(GCGmasterGetOrigprob(scip)), NULL, NULL) );
   SCIP_CALL( SCIPaddRealParam(GCGmasterGetOrigprob(scip), "sepa/basis/objconvex", "convex combination factor",
         &(sepadata->objconvex), FALSE, 1.0, 0.0, 1.0, NULL, NULL) );
   SCIP_CALL( SCIPaddIntParam(GCGmasterGetOrigprob(scip), "sepa/basis/paramsetting", "parameter returns which parameter setting is used for "
      "separation (default = 0, aggressive = 1, fast = 2", &(sepadata->separationsetting), FALSE, 1, 0, 2, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/chgobj", "parameter returns if basis is searched with different objective",
      &(sepadata->chgobj), FALSE, TRUE, NULL, NULL) );
   SCIP_CALL( SCIPaddIntParam(GCGmasterGetOrigprob(scip), "sepa/basis/iterations", "parameter returns if number new rows adding"
      "iterations (rows just cut off probing lp sol)", &(sepadata->iterations), FALSE, 100, 1, 10000000 , NULL, NULL) );
   SCIP_CALL( SCIPaddIntParam(GCGmasterGetOrigprob(scip), "sepa/basis/mincuts", "parameter returns number of minimum cuts needed to "
      "return *result = SCIP_Separated", &(sepadata->mincuts), FALSE, 1, 1, 100, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/chgobjallways", "parameter returns if obj is changed not only in the "
      "first iteration", &(sepadata->chgobjallways), FALSE, FALSE, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/basis/forcecuts", "parameter returns if cuts are forced to enter the LP ",
      &(sepadata->forcecuts), FALSE, FALSE, NULL, NULL) );

   return SCIP_OKAY;
}

/** returns the array of original cuts saved in the separator data */
SCIP_ROW** GCGsepaBasisGetOrigcuts(
   SCIP*                 scip                /**< SCIP data structure */
   )
{
   SCIP_SEPA* sepa;
   SCIP_SEPADATA* sepadata;

   assert(scip != NULL);

   sepa = SCIPfindSepa(scip, SEPA_NAME);
   assert(sepa != NULL);

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   return sepadata->origcuts;
}

/** returns the number of original cuts saved in the separator data */
int GCGsepaBasisGetNOrigcuts(
   SCIP*                 scip                /**< SCIP data structure */
   )
{
   SCIP_SEPA* sepa;
   SCIP_SEPADATA* sepadata;

   assert(scip != NULL);

   sepa = SCIPfindSepa(scip, SEPA_NAME);
   assert(sepa != NULL);

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   return sepadata->norigcuts;
}

/** returns the array of master cuts saved in the separator data */
SCIP_ROW** GCGsepaBasisGetMastercuts(
   SCIP*                 scip                /**< SCIP data structure */
   )
{
   SCIP_SEPA* sepa;
   SCIP_SEPADATA* sepadata;

   assert(scip != NULL);

   sepa = SCIPfindSepa(scip, SEPA_NAME);
   assert(sepa != NULL);

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   return sepadata->mastercuts;
}

/** returns the number of master cuts saved in the separator data */
int GCGsepaBasisGetNMastercuts(
   SCIP*                 scip                /**< SCIP data structure */
   )
{
   SCIP_SEPA* sepa;
   SCIP_SEPADATA* sepadata;

   assert(scip != NULL);

   sepa = SCIPfindSepa(scip, SEPA_NAME);
   assert(sepa != NULL);

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   return sepadata->nmastercuts;
}

/** transforms cut in pricing variables to cut in original variables and adds it to newcuts array */
SCIP_RETCODE GCGsepaBasisAddPricingCut(
   SCIP*                scip,
   int                  ppnumber,
   SCIP_ROW*            cut
   )
{
   SCIP* origscip;
   SCIP_SEPA* sepa;
   SCIP_SEPADATA* sepadata;

   SCIP* pricingprob;
   SCIP_Real* vals;
   SCIP_COL** cols;
   SCIP_VAR** pricingvars;
   int nvars;

   int i;
   int j;
   int k;

   char name[SCIP_MAXSTRLEN];

   assert(GCGisMaster(scip));

   sepa = SCIPfindSepa(scip, SEPA_NAME);

   if( sepa == NULL )
   {
      SCIPerrorMessage("sepa basis not found\n");
      return SCIP_OKAY;
   }

   sepadata = SCIPsepaGetData(sepa);
   origscip = GCGmasterGetOrigprob(scip);
   pricingprob = GCGgetPricingprob(origscip, ppnumber);

   if( !sepadata->enableppcuts )
   {
      return SCIP_OKAY;
   }

   assert(!SCIProwIsLocal(cut));

   nvars = SCIProwGetNNonz(cut);
   cols = SCIProwGetCols(cut);
   vals = SCIProwGetVals(cut);

   if( nvars == 0 )
   {
      return SCIP_OKAY;
   }

   SCIP_CALL( SCIPallocMemoryArray(scip, &pricingvars, nvars) );

   for( i = 0; i < nvars; ++i )
   {
      pricingvars[i] = SCIPcolGetVar(cols[i]);
      assert(pricingvars[i] != NULL);
   }

   for( k = 0; k < GCGgetNIdenticalBlocks(origscip, ppnumber); ++k )
   {
      SCIP_ROW* origcut;

      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "ppcut_%d_%d_%d", SCIPsepaGetNCalls(sepa), ppnumber, k);

      SCIP_CALL( SCIPcreateEmptyRowUnspec(origscip, &origcut, name,
         ( SCIPisInfinity(pricingprob, -SCIProwGetLhs(cut)) ?
            -SCIPinfinity(origscip) : SCIProwGetLhs(cut) - SCIProwGetConstant(cut)),
         ( SCIPisInfinity(pricingprob, SCIProwGetRhs(cut)) ?
            SCIPinfinity(origscip) : SCIProwGetRhs(cut) - SCIProwGetConstant(cut)),
             FALSE, FALSE, TRUE) );

      for( j = 0; j < nvars ; ++j )
      {
         SCIP_VAR* var;

         if( !GCGvarIsPricing(pricingvars[j]) )
         {
            nvars = 0;
            break;
         }
         assert(GCGvarIsPricing(pricingvars[j]));

         var = GCGpricingVarGetOrigvars(pricingvars[j])[k];
         assert(var != NULL);

         SCIP_CALL( SCIPaddVarToRow(origscip, origcut, var, vals[j]) );
      }

      if( nvars > 0 )
      {
         SCIP_CALL( ensureSizeNewCuts(scip, sepadata, sepadata->nnewcuts + 1) );

         sepadata->newcuts[sepadata->nnewcuts] = origcut;
         SCIP_CALL( SCIPcaptureRow(scip, sepadata->newcuts[sepadata->nnewcuts]) );
         ++(sepadata->nnewcuts);

         SCIPdebugMessage("cut added to orig cut pool\n");
      }
      SCIP_CALL( SCIPreleaseRow(origscip, &origcut) );
   }

   SCIPfreeMemoryArray(scip, &pricingvars);

   return SCIP_OKAY;
}

/** add cuts which are due to the latest objective function of the pricing problems
 *  (reduced cost non-negative) */
SCIP_RETCODE SCIPsepaBasisAddPPObjConss(
   SCIP*                scip,               /**< SCIP data structure */
   int                  ppnumber,           /**< number of pricing problem */
   SCIP_Real            dualsolconv,        /**< dual solution corresponding to convexity constraint */
   SCIP_Bool            newcuts             /**< add cut to newcuts in sepadata? (otherwise add it just to the cutpool) */
)
{
   SCIP_SEPA* sepa;

   assert(GCGisMaster(scip));

   sepa = SCIPfindSepa(scip, SEPA_NAME);

   if( sepa == NULL )
   {
      SCIPerrorMessage("sepa basis not found\n");
      return SCIP_OKAY;
   }

   SCIP_CALL( addPPObjConss(GCGmasterGetOrigprob(scip), sepa, ppnumber, dualsolconv, newcuts, FALSE) );

   return SCIP_OKAY;
}


// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright 2005-2016 Brian Roark and Google, Inc.
// Classes to generate random sentences from an LM or more generally
// paths through any FST where epsilons are treated as failure transitions.

#ifndef NGRAM_NGRAM_RANDGEN_H_
#define NGRAM_NGRAM_RANDGEN_H_

#include <sys/types.h>
#include <unistd.h>

#include <vector>

// Faster multinomial sampling possible if Gnu Scientific Library available.
#ifdef HAVE_GSL
#include <gsl/gsl_randist.h>
#include <gsl/gsl_rng.h>
#endif  // HAVE_GSL

#include <fst/fst.h>
#include <fst/randgen.h>
#include <ngram/util.h>

namespace ngram {

using fst::Fst;
using fst::ArcIterator;
using fst::LogWeight;
using fst::Log64Weight;

// Same as FastLogProbArcSelector but treats *all* epsilons as
// failure transitions that have a backoff weight. The LM must
// be fully normalized.
template <class A>
class NGramArcSelector {
 public:
  typedef typename A::StateId StateId;
  typedef typename A::Weight Weight;

  explicit NGramArcSelector(int seed = time(0) + getpid()) : seed_(seed) {
    srand(seed);
  }

  // Samples one transition.
  size_t operator()(const Fst<A> &fst, StateId s, double total_prob,
                    fst::CacheLogAccumulator<A> *accumulator) const {
    double r = rand() / (RAND_MAX + 1.0);
    // In effect, subtract out excess mass from the cumulative distribution.
    // Requires the backoff epsilon be the initial transition.
    double z = r + total_prob - 1.0;
    if (z <= 0.0) return 0;
    ArcIterator<Fst<A> > aiter(fst, s);
    return accumulator->LowerBound(-log(z), &aiter);
  }

  int Seed() const { return seed_; }

 private:
  int seed_;
  fst::WeightConvert<Weight, LogWeight> to_log_weight_;
};

}  // namespace ngram

namespace fst {

// Specialization for NGramArcSelector.
template <class A>
class ArcSampler<A, ngram::NGramArcSelector<A> > {
 public:
  typedef ngram::NGramArcSelector<A> S;
  typedef typename A::StateId StateId;
  typedef typename A::Weight Weight;
  typedef typename A::Label Label;
  typedef CacheLogAccumulator<A> C;

  ArcSampler(const Fst<A> &fst, const S &arc_selector, int max_length = INT_MAX)
      : fst_(fst),
        arc_selector_(arc_selector),
        max_length_(max_length),
        matcher_(fst_, MATCH_INPUT) {
    // Ensure the input FST has any epsilons as the initial transitions.
    if (!fst_.Properties(kILabelSorted, true))
      NGRAMERROR() << "ArcSampler:  is not input-label sorted";
    accumulator_.reset(new C());
    accumulator_->Init(fst);
#ifdef HAVE_GSL
    rng_ = gsl_rng_alloc(gsl_rng_taus);
    gsl_rng_set(rng_, arc_selector.Seed());
#endif  // HAVE_GSL
  }

  ArcSampler(const ArcSampler<A, S> &sampler, const Fst<A> *fst = 0)
      : fst_(fst ? *fst : sampler.fst_),
        arc_selector_(sampler.arc_selector_),
        max_length_(sampler.max_length_),
        matcher_(fst_, MATCH_INPUT) {
    if (fst) {
      accumulator_.reset(new C());
      accumulator_->Init(*fst);
    } else {  // shallow copy
      accumulator_.reset(new C(*sampler.accumulator_));
    }
  }

  ~ArcSampler() {
#ifdef HAVE_GSL
    gsl_rng_free(rng_);
#endif  // HAVE_GSL
  }

  bool Sample(const RandState<A> &rstate) {
    sample_map_.clear();
    forbidden_labels_.clear();

    if ((fst_.NumArcs(rstate.state_id) == 0 &&
         fst_.Final(rstate.state_id) == Weight::Zero()) ||
        rstate.length == max_length_) {
      Reset();
      return false;
    }

    double total_prob = TotalProb(rstate.state_id);

#ifdef HAVE_GSL
    if (fst_.NumArcs(rstate.state_id) + 1 < rstate.nsamples) {
      Weight numer_weight, denom_weight;
      BackoffWeight(rstate.state_id, total_prob, &numer_weight, &denom_weight);
      MultinomialSample(rstate, numer_weight);
      Reset();
      return true;
    }
#endif  // HAVE_GSL

    ArcIterator<Fst<A> > aiter(fst_, rstate.state_id);

    for (size_t i = 0; i < rstate.nsamples; ++i) {
      size_t pos = 0;
      Label label = kNoLabel;
      do {
        pos = arc_selector_(fst_, rstate.state_id, total_prob,
                            accumulator_.get());
        if (pos < fst_.NumArcs(rstate.state_id)) {
          aiter.Seek(pos);
          label = aiter.Value().ilabel;
        } else {
          label = kNoLabel;
        }
      } while (ForbiddenLabel(label, rstate));
      ++sample_map_[pos];
    }
    Reset();
    return true;
  }

  bool Done() const { return sample_iter_ == sample_map_.end(); }
  void Next() { ++sample_iter_; }
  std::pair<size_t, size_t> Value() const { return *sample_iter_; }
  void Reset() { sample_iter_ = sample_map_.begin(); }
  bool Error() const { return false; }

 private:
  double TotalProb(StateId s) {
    // Get cumulative weight at the state.
    ArcIterator<Fst<A> > aiter(fst_, s);
    accumulator_->SetState(s);
    Weight total_weight =
        accumulator_->Sum(fst_.Final(s), &aiter, 0, fst_.NumArcs(s));
    return exp(-to_log_weight_(total_weight).Value());
  }

  void BackoffWeight(StateId s, double total_prob, Weight *numer_weight,
                     Weight *denom_weight);

#ifdef HAVE_GSL
  void MultinomialSample(const RandState<A> &rstate, Weight fail_weight);
#endif  // HAVE_GSL

  bool ForbiddenLabel(Label l, const RandState<A> &rstate);

  const Fst<A> &fst_;
  const S &arc_selector_;
  int max_length_;

  // Stores (N, K) as described for Value().
  std::map<size_t, size_t> sample_map_;
  std::map<size_t, size_t>::const_iterator sample_iter_;
  std::unique_ptr<C> accumulator_;

#ifdef HAVE_GSL
  gsl_rng *rng_;              // GNU Sci Lib random number generator
  vector<double> pr_;         // multinomial parameters
  vector<unsigned int> pos_;  // sample positions
  vector<unsigned int> n_;    // sample counts
#endif                        // HAVE_GSL

  WeightConvert<Log64Weight, Weight> to_weight_;
  WeightConvert<Weight, Log64Weight> to_log_weight_;
  std::set<Label>
      forbidden_labels_;  // labels forbidden for failure transitions
  Matcher<Fst<A> > matcher_;
};

// Finds and decomposes the backoff probability into its numerator and
// denominator.
template <class A>
void ArcSampler<A, ngram::NGramArcSelector<A> >::BackoffWeight(
    StateId s, double total, Weight *numer_weight, Weight *denom_weight) {
  // Get backoff prob.
  double backoff = 0.0;
  matcher_.SetState(s);
  matcher_.Find(0);
  for (; !matcher_.Done(); matcher_.Next()) {
    const A &arc = matcher_.Value();
    if (arc.ilabel != kNoLabel) {  // not an implicit epsilon loop
      backoff = exp(-to_log_weight_(arc.weight).Value());
      break;
    }
  }

  if (backoff == 0.0) {  // no backoff transition
    *numer_weight = Weight::Zero();
    *denom_weight = Weight::Zero();
    return;
  }

  // total = 1 - numer + backoff
  double numer = 1.0 + backoff - total;
  *numer_weight = to_weight_(-log(numer));

  // backoff = numer/denom
  double denom = numer / backoff;
  *denom_weight = to_weight_(-log(denom));
}

#ifdef HAVE_GSL
template <class A>
void ArcSampler<A, ngram::NGramArcSelector<A> >::MultinomialSample(
    const RandState<A> &rstate, Weight fail_weight) {
  pr_.clear();
  pos_.clear();
  n_.clear();
  size_t pos = 0;
  for (ArcIterator<Fst<A> > aiter(fst_, rstate.state_id); !aiter.Done();
       aiter.Next(), ++pos) {
    const A &arc = aiter.Value();
    if (!ForbiddenLabel(arc.ilabel, rstate)) {
      pos_.push_back(pos);
      Weight weight = arc.ilabel == 0 ? fail_weight : arc.weight;
      pr_.push_back(exp(-to_log_weight_(weight).Value()));
    }
  }
  if (fst_.Final(rstate.state_id) != Weight::Zero() &&
      !ForbiddenLabel(kNoLabel, rstate)) {
    pos_.push_back(pos);
    pr_.push_back(exp(-to_log_weight_(fst_.Final(rstate.state_id)).Value()));
  }

  if (rstate.nsamples < UINT_MAX) {
    n_.resize(pr_.size());
    gsl_ran_multinomial(rng_, pr_.size(), rstate.nsamples, &(pr_[0]), &(n_[0]));
    for (size_t i = 0; i < n_.size(); ++i)
      if (n_[i] != 0) sample_map_[pos_[i]] = n_[i];
  } else {
    for (size_t i = 0; i < pr_.size(); ++i)
      sample_map_[pos_[i]] = ceil(pr_[i] * rstate.nsamples);
  }
}
#endif  // HAVE_GSL

template <class A>
bool ArcSampler<A, ngram::NGramArcSelector<A> >::ForbiddenLabel(
    Label l, const RandState<A> &rstate) {
  if (l == 0) return false;

  if (fst_.NumArcs(rstate.state_id) > rstate.nsamples) {
    for (const RandState<A> *rs = &rstate; rs->parent != 0; rs = rs->parent) {
      StateId parent_id = rs->parent->state_id;
      ArcIterator<Fst<A> > aiter(fst_, parent_id);
      aiter.Seek(rs->select);
      if (aiter.Value().ilabel != 0)  // not backoff transition
        return false;

      if (l == kNoLabel) {  // super-final label
        return fst_.Final(parent_id) != Weight::Zero();
      } else {
        matcher_.SetState(parent_id);
        if (matcher_.Find(l)) return true;
      }
    }
    return false;
  } else {
    if (forbidden_labels_.empty()) {
      for (const RandState<A> *rs = &rstate; rs->parent != 0; rs = rs->parent) {
        StateId parent_id = rs->parent->state_id;
        ArcIterator<Fst<A> > aiter(fst_, parent_id);
        aiter.Seek(rs->select);
        if (aiter.Value().ilabel != 0)  // not backoff transition
          break;

        for (aiter.Reset(); !aiter.Done(); aiter.Next()) {
          Label l = aiter.Value().ilabel;
          if (l != 0) forbidden_labels_.insert(l);
        }

        if (fst_.Final(parent_id) != Weight::Zero())
          forbidden_labels_.insert(kNoLabel);
      }
    }
    return forbidden_labels_.count(l) > 0;
  }
}

}  // namespace fst

#endif  // NGRAM_NGRAM_RANDGEN_H_


#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <Accelerate/Accelerate.h>

#include "infmcmc.h"

#define nj1 32
#define nk1 32

void infmcmc_initChain(INFCHAIN *C, const int nj, const int nk) {
  const int maxk      = (nk >> 1) + 1;
  const int sspectral = sizeof(fftw_complex) * nj * maxk;
  const int sphysical = sizeof(double      ) * nj * nk;
  //const int obsVecMem = sizeof(double      ) * sizeObsVector;
  FILE *fp;
  unsigned long int seed;

  // Set up variables
  C->nj = nj;
  C->nk = nk;
  //C->sizeObsVector = sizeObsVector;
  C->currentIter = 0;
  C->accepted = 0;
  C->_shortTimeAccProbAvg = 0.0;
  C->_bLow = 0.0;
  C->_bHigh = 1.0;

  // Allocate a ton of memory
  C->currentPhysicalState      = (double *)malloc(sphysical);
  C->avgPhysicalState          = (double *)malloc(sphysical);
  C->varPhysicalState          = (double *)malloc(sphysical);
  C->proposedPhysicalState     = (double *)malloc(sphysical);
  C->_M2                       = (double *)malloc(sphysical);
  //C->currentStateObservations  = (double *)malloc(obsVecMem);
  //C->proposedStateObservations = (double *)malloc(obsVecMem);
  //C->data                      = (double *)malloc(obsVecMem);

  C->currentSpectralState  = (fftw_complex *)fftw_malloc(sspectral);
  C->avgSpectralState      = (fftw_complex *)fftw_malloc(sspectral);
  C->priorDraw             = (fftw_complex *)fftw_malloc(sspectral);
  C->proposedSpectralState = (fftw_complex *)fftw_malloc(sspectral);

  memset(C->currentPhysicalState,  0, sphysical);
  memset(C->avgPhysicalState,      0, sphysical);
  memset(C->varPhysicalState,      0, sphysical);
  memset(C->proposedPhysicalState, 0, sphysical);
  memset(C->_M2,                   0, sphysical);
  memset(C->currentSpectralState,  0, sspectral);
  memset(C->avgSpectralState,      0, sspectral);
  memset(C->proposedSpectralState, 0, sspectral);

  C->accProb = 0.0;
  C->avgAccProb = 0.0;
  C->logLHDCurrentState = 0.0;

  /*
   * Set some default values
   */
  C->alphaPrior = 3.0;
  C->rwmhStepSize = 1e-4;
  C->priorVar = 1.0;
  C->priorStd = 1.0;

  C->r = gsl_rng_alloc(gsl_rng_taus2);

  fp = fopen("/dev/urandom", "rb");

  if (fp != NULL) {
    fread(&seed, sizeof(unsigned long int), 1, fp);
    gsl_rng_set(C->r, seed);
    fclose(fp);
    printf("Using random seed\n");
  }
  else {
    gsl_rng_set(C->r, 0);
    printf("Using zero seed\n");
  }

  C->_c2r = fftw_plan_dft_c2r_2d(nj, nk, C->proposedSpectralState, C->proposedPhysicalState, FFTW_MEASURE);
  C->_r2c = fftw_plan_dft_r2c_2d(nj, nk, C->currentPhysicalState, C->currentSpectralState, FFTW_MEASURE);
}

void infmcmc_freeChain(INFCHAIN *C) {
  // Free all allocated memory used by the chain
  free(C->currentPhysicalState);
  free(C->avgPhysicalState);
  free(C->varPhysicalState);
  free(C->proposedPhysicalState);
  free(C->_M2);
  //free(C->currentStateObservations);
  //free(C->proposedStateObservations);

  fftw_free(C->currentSpectralState);
  fftw_free(C->avgSpectralState);
  fftw_free(C->priorDraw);
  fftw_free(C->proposedSpectralState);

  gsl_rng_free(C->r);
}

void infmcmc_resetChain(INFCHAIN *C) {
  infmcmc_freeChain(C);
  infmcmc_initChain(C, C->nj, C->nk);
}

void infmcmc_writeChain(const INFCHAIN *C, FILE *fp) {
  const int s = C->nj * C->nk;

  fwrite(&(C->nj),                 sizeof(int),    1,         fp);
  fwrite(&(C->nk),                 sizeof(int),    1,         fp);
  fwrite(&(C->currentIter),        sizeof(int),    1,         fp);
  fwrite(C->currentPhysicalState,  sizeof(double), s,         fp);
  fwrite(C->avgPhysicalState,      sizeof(double), s,         fp);
  fwrite(C->varPhysicalState,      sizeof(double), s,         fp);
  fwrite(&(C->logLHDCurrentState), sizeof(double), 1,         fp);
  fwrite(&(C->accProb),            sizeof(double), 1,         fp);
  fwrite(&(C->avgAccProb),         sizeof(double), 1,         fp);
}

void infmcmc_writeChainInfo(const INFCHAIN *C, FILE *fp) {
  fwrite(&(C->nj),             sizeof(int), 1, fp);
  fwrite(&(C->nk),             sizeof(int), 1, fp);
}

void infmcmc_writeVFChain(const INFCHAIN *U, const INFCHAIN *V, FILE *fp) {
  const int s = U->nj * U->nk;

  fwrite(U->currentPhysicalState,  sizeof(double), s,         fp);
  fwrite(U->avgPhysicalState,      sizeof(double), s,         fp);
  fwrite(U->varPhysicalState,      sizeof(double), s,         fp);
  fwrite(V->currentPhysicalState,  sizeof(double), s,         fp);
  fwrite(V->avgPhysicalState,      sizeof(double), s,         fp);
  fwrite(V->varPhysicalState,      sizeof(double), s,         fp);
  fwrite(&(U->logLHDCurrentState), sizeof(double), 1,         fp);
  fwrite(&(U->accProb),            sizeof(double), 1,         fp);
  fwrite(&(U->avgAccProb),         sizeof(double), 1,         fp);
}

void infmcmc_printChain(INFCHAIN *C) {
  printf("Iteration %d\n", C->currentIter);
  printf("-- Length is         %d x %d\n", C->nj, C->nk);
  printf("-- llhd val is       %lf\n", C->logLHDCurrentState);
  printf("-- Acc. prob is      %.10lf\n", C->accProb);
  printf("-- Avg. acc. prob is %.10lf\n", C->avgAccProb);
  printf("-- Beta is           %.10lf\n\n", C->rwmhStepSize);
  //finmcmc_printCurrentState(C);
  //finmcmc_printAvgState(C);
  //finmcmc_printVarState(C);
}

void randomPriorDraw(INFCHAIN *C) {
  int j, k;
  const int maxk = (C->nk >> 1) + 1;
  const int nko2 = C->nk >> 1;
  const int njo2 = C->nj >> 1;
  double xrand, yrand, c;
  //const double one = 1.0;

  c = 4.0 * M_PI * M_PI;

  for(j = 0; j < C->nj; j++) {
    for(k = 0; k < maxk; k++) {
      xrand = gsl_ran_gaussian_ziggurat(C->r, C->priorStd);
      if((j == 0) && (k == 0)) {
        C->priorDraw[0] = 0.0;
      }
      else if((j == njo2) && (k == nko2)) {
        C->priorDraw[maxk*njo2+nko2] = /*C->nj */ xrand / pow(c * ((j * j) + (k * k)), (double)C->alphaPrior/2.0);
      }
      else if((j == 0) && (k == nko2)) {
        C->priorDraw[nko2] = /*C->nj */ xrand / pow(c * ((j * j) + (k * k)), (double)C->alphaPrior/2.0);
      }
      else if((j == njo2) && (k == 0)) {
        C->priorDraw[maxk*njo2] = /*C->nj */ xrand / pow(c * ((j * j) + (k * k)), (double)C->alphaPrior/2.0);
      }
      else {
        xrand /= sqrt(2.0);
        yrand = gsl_ran_gaussian_ziggurat(C->r, C->priorStd) / sqrt(2.0);
        C->priorDraw[maxk*j+k] = /*C->nj */ (xrand + I * yrand) / pow(c * ((j * j) + (k * k)), (double)C->alphaPrior/2.0);
        if(j > njo2) {
          C->priorDraw[maxk*j+k] = conj(C->priorDraw[maxk*(C->nj-j)+k]);
        }
      }
    }
  }
}

void randomDivFreePriorDraw(INFCHAIN *C1, INFCHAIN *C2) {
  int j, k;
  const int maxk = (C1->nk >> 1) + 1;
  const int njo2 = C2->nj >> 1;
  const int nko2 = C1->nk >> 1;
  double modk;

  randomPriorDraw(C1);

  for (j = 0; j < C1->nj; j++) {
    for (k = 0; k < maxk; k++) {
      if (j == 0 && k == 0) {
        C1->priorDraw[0] = 0.0;
        C2->priorDraw[0] = 0.0;
        continue;
      }

      modk = sqrt(j * j + k * k);
      if (j < njo2) {
        C2->priorDraw[maxk*j+k] = -j * C1->priorDraw[maxk*j+k] / modk;
      }
      else if (j > njo2) {
        C2->priorDraw[maxk*j+k] = -(j - C1->nj) * C1->priorDraw[maxk*j+k] / modk;
      }
      else {
        C2->priorDraw[maxk*j+k] = 0.0;
      }

      if (k < nko2) {
        C1->priorDraw[maxk*j+k] *= k / modk;
      }
      else {
        C1->priorDraw[maxk*j+k] = 0.0;
      }
    }
  }
}

void infmcmc_seedWithPriorDraw(INFCHAIN *C) {
  const int size = sizeof(fftw_complex) * C->nj * ((C->nk >> 1) + 1);
  fftw_complex *uk = (fftw_complex *)fftw_malloc(size);
  const fftw_plan p = fftw_plan_dft_c2r_2d(C->nj, C->nk, uk, C->currentPhysicalState, FFTW_ESTIMATE);

  randomPriorDraw(C);
  memcpy(uk, C->priorDraw, size);

  //fixme: put into current spectral state

  fftw_execute(p);
  fftw_destroy_plan(p);
  fftw_free(uk);
}

void infmcmc_seedWithDivFreePriorDraw(INFCHAIN *C1, INFCHAIN *C2) {
  const int size = sizeof(fftw_complex) * C1->nj * ((C1->nk >> 1) + 1);
  fftw_complex *uk = (fftw_complex *)fftw_malloc(size);
  const fftw_plan p = fftw_plan_dft_c2r_2d(C1->nj, C1->nk, uk, C1->currentPhysicalState, FFTW_ESTIMATE);

  randomDivFreePriorDraw(C1, C2);

  memcpy(uk, C1->priorDraw, size);
  fftw_execute_dft_c2r(p, uk, C1->currentPhysicalState);

  memcpy(uk, C2->priorDraw, size);
  fftw_execute_dft_c2r(p, uk, C2->currentPhysicalState);

  memcpy(C1->currentSpectralState, C1->priorDraw, size);
  memcpy(C2->currentSpectralState, C2->priorDraw, size);

  fftw_destroy_plan(p);
  fftw_free(uk);
}

void infmcmc_proposeRWMH(INFCHAIN *C) {
  int j, k;
  const int maxk = (C->nk >> 1) + 1;
  const int N = C->nj * C->nk;
  const double sqrtOneMinusBeta2 = sqrt(1.0 - C->rwmhStepSize * C->rwmhStepSize);
  double *u = (double *)malloc(sizeof(double) * C->nj * C->nk);
  fftw_complex *uk = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * C->nj * maxk);

  memcpy(u, C->currentPhysicalState, sizeof(double) * C->nj * C->nk);
  fftw_execute_dft_r2c(C->_r2c, u, C->currentSpectralState);

  // Draw from prior distribution
  randomPriorDraw(C);

  for(j = 0; j < C->nj; j++) {
    for(k = 0; k < maxk; k++) {
      C->proposedSpectralState[maxk*j+k] = sqrtOneMinusBeta2 * C->currentSpectralState[maxk*j+k] + C->rwmhStepSize * C->priorDraw[maxk*j+k];
      C->proposedSpectralState[maxk*j+k] /= N;
    }
  }

  memcpy(uk, C->proposedSpectralState, sizeof(fftw_complex) * C->nj * maxk);
  fftw_execute_dft_c2r(C->_c2r, uk, C->proposedPhysicalState);
  fftw_free(uk);
  free(u);
}

void infmcmc_adaptRWMHStepSize(INFCHAIN *C, double inc) {
  // Adapt to stay in 20-30% range.
  int adaptFreq = 100;
  double rate;

  if (C->currentIter > 0 && C->currentIter % adaptFreq == 0) {
    rate = (double) C->_shortTimeAccProbAvg / adaptFreq;

    if (rate < 0.2) {
      //C->_bHigh = C->rwmhStepSize;
      //C->rwmhStepSize = (C->_bLow + C->_bHigh) / 2.0;
      C->rwmhStepSize -= inc;
    }
    else if (rate > 0.3) {
      //C->_bLow = C->rwmhStepSize;
      //C->rwmhStepSize = (C->_bLow + C->_bHigh) / 2.0;
      C->rwmhStepSize += inc;
    }

    C->_shortTimeAccProbAvg = 0.0;
  }
  else {
    C->_shortTimeAccProbAvg += C->accProb;
  }
}

void infmcmc_proposeDivFreeRWMH(INFCHAIN *C1, INFCHAIN *C2) {
  int j, k;
  const int maxk = (C1->nk >> 1) + 1;
  const int N = C1->nj * C1->nk;
  const double sqrtOneMinusBeta2 = sqrt(1.0 - C1->rwmhStepSize * C1->rwmhStepSize);
  double *u = (double *)malloc(sizeof(double) * C1->nj * C1->nk);
  fftw_complex *uk = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * C1->nj * maxk);

  memcpy(u, C1->currentPhysicalState, sizeof(double) * C1->nj * C1->nk);
  fftw_execute_dft_r2c(C1->_r2c, u, C1->currentSpectralState);

  memcpy(u, C2->currentPhysicalState, sizeof(double) * C2->nj * C2->nk);
  fftw_execute_dft_r2c(C2->_r2c, u, C2->currentSpectralState);

  // Draw from prior distribution
  randomDivFreePriorDraw(C1, C2);

  for(j = 0; j < C1->nj; j++) {
    for(k = 0; k < maxk; k++) {
      C1->currentSpectralState[maxk*j+k] /= N;
      C2->currentSpectralState[maxk*j+k] /= N;
      C1->proposedSpectralState[maxk*j+k] = sqrtOneMinusBeta2 * C1->currentSpectralState[maxk*j+k] + C1->rwmhStepSize * C1->priorDraw[maxk*j+k];
      //C1->proposedSpectralState[maxk*j+k] /= N;
      C2->proposedSpectralState[maxk*j+k] = sqrtOneMinusBeta2 * C2->currentSpectralState[maxk*j+k] + C2->rwmhStepSize * C2->priorDraw[maxk*j+k];
      //C2->proposedSpectralState[maxk*j+k] /= N;
    }
  }

  memcpy(uk, C1->proposedSpectralState, sizeof(fftw_complex) * C1->nj * maxk);
  fftw_execute_dft_c2r(C1->_c2r, uk, C1->proposedPhysicalState);
  memcpy(uk, C2->proposedSpectralState, sizeof(fftw_complex) * C1->nj * maxk);
  fftw_execute_dft_c2r(C2->_c2r, uk, C2->proposedPhysicalState);

  fftw_free(uk);
  free(u);
}

void infmcmc_updateAvgs(INFCHAIN *C) {
  int j, k;
  double deltar;
  fftw_complex deltac;
  C->currentIter++;

  /*
   Update physical vectors
   */
  if (C->currentIter == 1) {
    for (j = 0; j < C->nj; j++) {
      for (k = 0; k < C->nk; k++) {
        deltar = C->currentPhysicalState[C->nk * j + k] - C->avgPhysicalState[C->nk * j + k];
        C->avgPhysicalState[C->nk * j + k] += (deltar / C->currentIter);
        C->_M2[C->nk * j + k] += (deltar * (C->currentPhysicalState[C->nk * j + k] - C->avgPhysicalState[C->nk * j + k]));
        C->varPhysicalState[C->nk * j + k] = -1.0;
      }
    }
  }
  else {
    for (j = 0; j < C->nj; j++) {
      for (k = 0; k < C->nk; k++) {
        deltar = C->currentPhysicalState[C->nk * j + k] - C->avgPhysicalState[C->nk * j + k];
        C->avgPhysicalState[C->nk * j + k] += (deltar / C->currentIter);
        C->_M2[C->nk * j + k] += (deltar * (C->currentPhysicalState[C->nk * j + k] - C->avgPhysicalState[C->nk * j + k]));
        C->varPhysicalState[C->nk * j + k] = C->_M2[C->nk * j + k] / (C->currentIter - 1);
      }
    }
  }

  /*
   Update spectral vectors
  */
  if (C->currentIter == 1) {
    for (j = 0; j < C->nj; j++) {
      for (k = 0; k < C->nk/2 + 1; k++) {
        deltac = C->currentSpectralState[(C->nk/2 + 1) * j + k] - C->avgSpectralState[(C->nk/2 + 1) * j + k];
        C->avgSpectralState[(C->nk/2 + 1) * j + k] += (deltac / C->currentIter);
      }
    }
  }
  else {
    for (j = 0; j < C->nj; j++) {
      for (k = 0; k < C->nk/2 + 1; k++) {
        deltac = C->currentSpectralState[(C->nk/2 + 1) * j + k] - C->avgSpectralState[(C->nk/2 + 1) * j + k];
        C->avgSpectralState[(C->nk/2 + 1) * j + k] += (deltac / C->currentIter);
      }
    }
  }

  /*
   Update scalars
   */
  C->avgAccProb += ((C->accProb - C->avgAccProb) / C->currentIter);
}

void infmcmc_updateRWMH(INFCHAIN *C, double logLHDOfProposal) {
  double alpha;

  alpha = exp(C->logLHDCurrentState - logLHDOfProposal);

  if (alpha > 1.0) {
    alpha = 1.0;
  }
  // fixme: set acc prob here instead
  if (gsl_rng_uniform(C->r) < alpha) {
    memcpy(C->currentSpectralState, C->proposedSpectralState, sizeof(fftw_complex) * C->nj * ((C->nk >> 1) + 1));
    memcpy(C->currentPhysicalState, C->proposedPhysicalState, sizeof(double) * C->nj * C->nk);
    C->accProb = alpha;
    C->logLHDCurrentState = logLHDOfProposal;
  }

  infmcmc_updateAvgs(C);
}

void infmcmc_updateVectorFieldRWMH(INFCHAIN *C1, INFCHAIN *C2, double logLHDOfProposal) {
  double alpha;

  // log likelihoods will be the same for both chains
	alpha = exp(C1->logLHDCurrentState - logLHDOfProposal);

  if (alpha > 1.0) {
    alpha = 1.0;
  }

  C1->accepted = 0;
  C2->accepted = 0;
  C1->accProb = alpha;
  C2->accProb = alpha;

  if (gsl_rng_uniform(C1->r) < alpha) {
    C1->accepted = 1;
    C2->accepted = 1;
    memcpy(C1->currentSpectralState, C1->proposedSpectralState, sizeof(fftw_complex) * C1->nj * ((C1->nk >> 1) + 1));
    memcpy(C1->currentPhysicalState, C1->proposedPhysicalState, sizeof(double) * C1->nj * C1->nk);
    C1->logLHDCurrentState = logLHDOfProposal;
    memcpy(C2->currentSpectralState, C2->proposedSpectralState, sizeof(fftw_complex) * C2->nj * ((C2->nk >> 1) + 1));
    memcpy(C2->currentPhysicalState, C2->proposedPhysicalState, sizeof(double) * C2->nj * C2->nk);
    C2->logLHDCurrentState = logLHDOfProposal;
  }

  infmcmc_updateAvgs(C1);
  infmcmc_updateAvgs(C2);
}

void infmcmc_setRWMHStepSize(INFCHAIN *C, double beta) {
  C->rwmhStepSize = beta;
}

void infmcmc_setPriorAlpha(INFCHAIN *C, double alpha) {
  C->alphaPrior = alpha;
}

void infmcmc_setPriorVar(INFCHAIN *C, double var) {
  C->priorVar = var;
  C->priorStd = sqrt(var);
}

double L2Field(fftw_complex *uk, int nj, int nk) {
  int j, k;
  const int maxk = (nk >> 1) + 1;
  double sum = 0.0;

  for (j = 0; j < nj; j++) {
    for (k = 0; k < maxk; k++) {
      sum += cabs(uk[maxk*j+k]) * cabs(uk[maxk*j+k]);
    }
  }

  return 2.0 * sum;
}

double infmcmc_L2Current(INFCHAIN *C) {
  return L2Field(C->currentSpectralState, C->nj, C->nk);
}

double infmcmc_L2Proposed(INFCHAIN *C) {
  return L2Field(C->proposedSpectralState, C->nj, C->nk);
}

double infmcmc_L2Prior(INFCHAIN *C) {
  return L2Field(C->priorDraw, C->nj, C->nk);
}

void randomPriorDrawOLD(gsl_rng *r, double PRIOR_ALPHA, fftw_complex *randDrawCoeffs) {
  int j, k;
  double xrand, yrand, c;//, scale;
  //const double one = 1.0;

  c = 4.0 * M_PI * M_PI;

  for(j = 0; j < nj1; j++) {
    for(k = 0; k < nk1/2 + 1; k++) {
      if((j == 0) && (k == 0)) {
        randDrawCoeffs[0] = 0.0;
      }
      else if((j == nj1/2) && (k == nk1/2)) {
        xrand = gsl_ran_gaussian_ziggurat(r, 1.0);
        randDrawCoeffs[(nk1/2 + 1) * nj1/2 + nk1/2] = xrand / pow((c * ((j * j) + (k * k))), (double)PRIOR_ALPHA/2.0);
      }
      else if((j == 0) && (k == nk1/2)) {
        xrand = gsl_ran_gaussian_ziggurat(r, 1.0);
        randDrawCoeffs[nk1/2] = xrand / pow((c * ((j * j) + (k * k))), (double)PRIOR_ALPHA/2.0);
      }
      else if((j == nj1/2) && (k == 0)) {
        xrand = gsl_ran_gaussian_ziggurat(r, 1.0);
        randDrawCoeffs[(nk1/2 + 1) * nj1/2] = xrand / pow((c * ((j * j) + (k * k))), (double)PRIOR_ALPHA/2.0);
      }
      else {
        xrand = gsl_ran_gaussian_ziggurat(r, 1.0) / sqrt(2.0);
        yrand = gsl_ran_gaussian_ziggurat(r, 1.0) / sqrt(2.0);
        randDrawCoeffs[(nk1/2 + 1) * j + k] = (xrand + I * yrand) / pow((c * ((j * j) + (k * k))), (double)PRIOR_ALPHA/2.0);
        if(j > nj1/2) {
          randDrawCoeffs[(nk1/2 + 1) * j + k] = conj(randDrawCoeffs[(nk1/2+1)*(nj1-j)+k]);
        }
      }
    }
  }

  /*
  for(j = 1; j < nj1 / 2; j++) {
    for(k = 0; k < nk1 / 2 + 1; k++) {
      xrand = gsl_ran_gaussian_ziggurat(r, 1.0) / M_SQRT2;
      yrand = gsl_ran_gaussian_ziggurat(r, 1.0) / M_SQRT2;
      scale = pow(c * ((j * j) + (k * k)), (double)PRIOR_ALPHA/2.0);
      randDrawCoeffs[(nk1/2 + 1) * j + k] = (xrand + I * yrand) / scale;
      randDrawCoeffs[(nk1/2 + 1) * (nj1-j) + k] = (xrand - I * yrand) / scale;
    }
  }

  for(k = 1; k < nk1 / 2 + 1; k++) {
    xrand = gsl_ran_gaussian_ziggurat(r, 1.0) / M_SQRT2;
    randDrawCoeffs[k] = (xrand + I * yrand) / pow(c * (k * k), (double)PRIOR_ALPHA/2.0);
  }

  for(k = 0; k < nk1/2; k++) {
    xrand = gsl_ran_gaussian_ziggurat(r, 1.0) / M_SQRT2;
    randDrawCoeffs[(nk1/2+1)*(nj1/2)+k] = (xrand + I * yrand) / pow(c * ((nj1 * nj1 / 4) + (k * k)), (double)PRIOR_ALPHA/2.0);
  }

  randDrawCoeffs[0] = 0.0;

  xrand = gsl_ran_gaussian_ziggurat(r, 1.0);
  randDrawCoeffs[(nk1/2+1)*(nj1/2)+(nk1/2)] = xrand / pow(c * ((j * j) + (k * k)), (double)PRIOR_ALPHA/2.0);
  */
}

void setRWMHStepSize(CHAIN *C, double stepSize) {
  C->rwmhStepSize = stepSize;
}

void resetAvgs(CHAIN *C) {
  /*
    Sets avgPhysicalState to currentPhysicalState and
         avgSpectralState to currentSpectralState
  */
  const size_t size_doublenj = sizeof(double) * C->nj;
  memcpy(C->avgPhysicalState, C->currentPhysicalState, size_doublenj * C->nk);
  memcpy(C->avgSpectralState, C->currentSpectralState, size_doublenj * ((C->nk >> 1) + 1));
}

void resetVar(CHAIN *C) {
  // Sets varPhysicalState to 0
  memset(C->varPhysicalState, 0, sizeof(double) * C->nj * C->nk);
}

void proposeIndependence(CHAIN *C) {
  const int maxk = (C->nk >> 1) + 1;

  memcpy(C->proposedSpectralState, C->priorDraw, sizeof(fftw_complex) * C->nj * maxk);
}

double lsqFunctional(const double * const data, const double * const obsVec, const int obsVecSize, const double obsStdDev) {
  int i;
  double temp1, sum1 = 0.0;

  for(i = 0; i < obsVecSize; i++) {
    temp1 = (data[i] - obsVec[i]);
    sum1 += temp1 * temp1;
  }

  return sum1 / (2.0 * obsStdDev * obsStdDev);
}

void acceptReject(CHAIN *C) {
  const double phi1 = lsqFunctional(C->data, C->currentStateObservations, C->sizeObsVector, C->obsStdDev);
  const double phi2 = lsqFunctional(C->data, C->proposedStateObservations, C->sizeObsVector, C->obsStdDev);
  double tempAccProb = exp(phi1 - phi2);

  if(tempAccProb > 1.0) {
    tempAccProb = 1.0;
  }

  if(gsl_rng_uniform(C->r) < tempAccProb) {
    memcpy(C->currentSpectralState, C->proposedSpectralState, sizeof(fftw_complex) * C->nj * ((C->nk >> 1) + 1));
    memcpy(C->currentPhysicalState, C->proposedPhysicalState, sizeof(double) * C->nj * C->nk);
    memcpy(C->currentStateObservations, C->proposedStateObservations, sizeof(double) * C->sizeObsVector);

    C->accProb = tempAccProb;
    C->currentLSQFunctional = phi2;
  }
  else {
    C->currentLSQFunctional = phi1;
  }
}

//
//void updateChain(CHAIN *C) {
//C->currentIter++;
//void updateAvgs(CHAIN *C);
//void updateVar(CHAIN *C);
/*
int main(void) {
  int nj = 32, nk = 32, sizeObsVector = 0;
  unsigned long int randseed = 0;

  FILE *fp;
  CHAIN *C;

  C = (CHAIN *)malloc(sizeof(CHAIN));

  initChain(C, nj, nk, sizeObsVector, randseed);

  randomPriorDraw2(C);

  fp = fopen("2.dat", "w");
  fwrite(C->priorDraw, sizeof(fftw_complex), nj * (nk / 2 + 1), fp);
  fclose(fp);

  return 0;
}
*/


/**
 * \author Sylvain Marsat, University of Maryland - NASA GSFC
 *
 * \brief C header for functions computing coeffcients of Not-A-Knot and Quadratic splines in matrix form.
 *
 */

#ifndef _FRESNEL_H
#define _FRESNEL_H

#define _XOPEN_SOURCE 500

#ifdef __GNUC__
#define UNUSED __attribute__ ((unused))
#else
#define UNUSED
#endif

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <stdbool.h>
#include <string.h>

#include <gsl/gsl_errno.h>
#include <gsl/gsl_bspline.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_min.h>
#include <gsl/gsl_spline.h>
#include <gsl/gsl_complex.h>

#include "constants.h"
#include "struct.h"

#if defined(__cplusplus)
#define complex _Complex
extern "C" {
#elif 0
} /* so that editors will match preceding brace */
#endif

double complex ComputeInt(
  gsl_matrix* splinecoeffsAreal,         /*  */
  gsl_matrix* splinecoeffsAimag,         /*  */
  gsl_matrix* splinecoeffsphase);        /*  */

double complex ComputeIntCase1a(
  const double complex* coeffsA,         /* */
  const double p1,                       /* */
  const double p2,                       /* */
  const double scale);                   /* */
double complex ComputeIntCase1b(
  const double complex* coeffsA,         /* */
  const double p1,                       /* */
  const double p2,                       /* */
  const double scale);                   /* */
double complex ComputeIntCase2(
  const double complex* coeffsA,         /* */
  const double p1,                       /* */
  const double p2);                      /* */
double complex ComputeIntCase3(
  const double complex* coeffsA,         /* */
  const double p1,                       /* */
  const double p2);                      /* */
double complex ComputeIntCase4(
  const double complex* coeffsA,         /* */
  const double p1,                       /* */
  const double p2);                      /* */

#if 0
{ /* so that editors will match succeeding brace */
#elif defined(__cplusplus)
}
#endif

#endif /* _FRESNEL_H */