/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                           */
/*                  This file is part of the program and library             */
/*         SCIP --- Solving Constraint Integer Programs                      */
/*                                                                           */
/*  Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB)                      */
/*                                                                           */
/*  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.                                           */
/*                                                                           */
/*  You should have received a copy of the Apache-2.0 license                */
/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
/*                                                                           */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**@file   cons_pseudoboolean.c
 * @ingroup DEFPLUGINS_CONS
 * @brief  constraint handler for pseudo Boolean constraints
 * @author Gerald Gamrath
 * @author Stefan Heinz
 * @author Michael Winkler
 * @author Dominik Kamp
 *
 * The constraint handler deals with pseudo Boolean constraints. These are constraints of the form
 * \f[
 * \mbox{lhs} \leq \sum_{k=0}^m c_k \cdot x_k  +  \sum_{i=0}^n c_i \cdot \prod_{j \in I_i} x_j \leq \mbox{rhs}
 * \f]
 * where all x are binary and all c are integer
 *
 * @todo Add eventhandling.
 */

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

#include "blockmemshell/memory.h"
#include "scip/cons_and.h"
#include "scip/cons_indicator.h"
#include "scip/cons_knapsack.h"
#include "scip/cons_linear.h"
#include "scip/cons_logicor.h"
#include "scip/cons_pseudoboolean.h"
#include "scip/cons_setppc.h"
#include "scip/cons_xor.h"
#include "scip/debug.h"
#include "scip/pub_cons.h"
#include "scip/pub_message.h"
#include "scip/pub_misc.h"
#include "scip/pub_misc_sort.h"
#include "scip/pub_var.h"
#include "scip/scip_cons.h"
#include "scip/scip_copy.h"
#include "scip/scip_general.h"
#include "scip/scip_mem.h"
#include "scip/scip_message.h"
#include "scip/scip_numerics.h"
#include "scip/scip_param.h"
#include "scip/scip_prob.h"
#include "scip/scip_sol.h"
#include "scip/scip_var.h"
#include "scip/symmetry_graph.h"
#include <string.h>

#ifdef WITHEQKNAPSACK
#include "scip/cons_eqknapsack.h"   /* cppcheck-suppress missingInclude */
#endif

/* constraint handler properties */
#define CONSHDLR_NAME          "pseudoboolean"
#define CONSHDLR_DESC          "constraint handler dealing with pseudo Boolean constraints"
#define CONSHDLR_ENFOPRIORITY  -1000000 /**< priority of the constraint handler for constraint enforcing */
#define CONSHDLR_CHECKPRIORITY -5000000 /**< priority of the constraint handler for checking feasibility */
#define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
                                              *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
#define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
#define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */

#define CONSHDLR_PRESOLTIMING            SCIP_PRESOLTIMING_MEDIUM /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */

#define DEFAULT_DECOMPOSENORMALPBCONS FALSE /**< decompose every normal pseudo boolean constraint into a "linear" constraint and "and" constraints */
#define DEFAULT_DECOMPOSEINDICATORPBCONS TRUE /**< decompose every soft pseudo boolean constraint into "indicator" constraints and "and" constraints */

#define DEFAULT_SEPARATENONLINEAR  TRUE /**< if decomposed, should the nonlinear constraints be separated during LP processing */
#define DEFAULT_PROPAGATENONLINEAR TRUE /**< if decomposed, should the nonlinear constraints be propagated during node processing */
#define DEFAULT_REMOVABLENONLINEAR TRUE /**< if decomposed, should the nonlinear constraints be removable */
#define NONLINCONSUPGD_PRIORITY   60000 /**< priority of upgrading nonlinear constraints */

/* remove this line to compile the upgrade from nonlinear to pseudoboolean constraints */
#undef NONLINCONSUPGD_PRIORITY  /*lint !e750*/

/*
 * Data structures
 */
#define HASHSIZE_PSEUDOBOOLEANNONLINEARTERMS 500 /**< minimal size of hash table in and constraint tables */


/* - create special linear(knapsack, setppc, logicor, (eqknapsack)) and and-constraints with check flags FALSE, to
 *   get smaller amount of locks on the term variables, do all presolving ...?! in these constraint handlers
 *
 * - do the checking here, lock and-resultants in both directions and all and-variables according to their
 *   coefficients and sides of the constraint,
 *   @note this only works if the and-resultant has no objective cofficient, otherwise we need to lock variables also in both directions
 *
 * - need to keep and constraint pointer for special propagations like if two ands are due to their variables in
 *   one clique, add this cliques of and-resultants
 *
 * - do special presolving like on instance :
 * check/IP/PseudoBoolean/normalized-PB07/OPT-SMALLINT-NLC/submittedPB07/manquinho/bsg/normalized-bsg_1000_25_1.opb.gz
 *
 *  there exist constraint like:        1 x1 x2 + 1 x1 x3 + 1 x1 x4 + 1 x1 x5 <= 1 ;
 *  which "equals" a linear constraint: 3 x1 + x2 + x3 + x4 + x5 <= 4 ;
 *
 *  in more general terms:                     1 x1 x2 x3 x4 + 1 x1 x2 x5 x6 x7 + 1 x1 x2 x8 x9 <= 1 ;
 *  which "equals" a pseudoboolean constraint: 2 x1 + 2 x2 + 1 x3 x4 + 1 x5 x6 x7 + 1 x8 x9 <= 5 ;
 *
 *  in an even more general terms:             5 x1 x2 x3 x4 + 1 x1 x2 x5 x6 x7 + 1 x1 x2 x8 x9 <= 6 ;
 *            equals(should the knapsack do)   1 x1 x2 x3 x4 + 1 x1 x2 x5 x6 x7 + 1 x1 x2 x8 x9 <= 2 ;
 *  which "equals" a pseudoboolean constraint: 2 x1 + 2 x2 + 1 x3 x4 + 1 x5 x6 x7 + 1 x8 x9 <= 6 ;
 *  (         without knapsack                 7 x1 + 7 x2 + 5 x3 x4 + 1 x5 x6 x7 + 1 x8 x9 <= 20 ; )
 *
 *  another special case :                     1 x1 x2 x3 + 1 x1 x2 x4 + 1 x5 x6 <= 1 ;
 *  which "equals" a pseudoboolean constraint: 2 x1 + 2 x2 + 1 x3 + 1 x4 + 1 x5 x6 <= 5 ;
 *  which "equals" a pseudoboolean constraint: 4 x1 + 4 x2 + 2 x3 + 2 x4 + 1 x5 + 1 x6 <= 10 ;
 *
 *  another special case :                     1 x1 x2 + 1 x1 x3 + 2 x4 x5 <= 3 ;
 *  which "equals" a pseudoboolean constraint: 2 x1 + 1 x2 + 1 x3 + 2 x4 x5 <= 5 ;
 *  which "equals" a pseudoboolean constraint: 2 x1 + 1 x2 + 1 x3 + 1 x4 + 1 x5 <= 5 ;
 */
/* @todo - in and-constraint better count nfixed zeros in both directions and maybe nfixedones for better propagation
 *
 *       - do better conflict analysis by choosing the earliest fixed variable which led to a conflict instead of maybe
 *         best coefficient or create more conflicts by using all to zero fixed variables one by one
 *
 *       - how to make sure that we aggregate in a right way, when aggregating a resultant and a "normal" variable,
 *         maybe add in SCIPaggregateVars a check for original variables, to prefer them if the variable type is the
 *         same; probably it would be better too if we would aggregate two resultants that the one with less variables
 *         inside the and-constraint will stay active
 *
 * @note since product resultants are artificial, we do not care for their solution value, but this can lead to fixation
 *       of the resultant not representing the product, in 'optimization mode' we do not care, but this might make
 *       solution debugging complicated
 */

/** and-constraint data object */
struct ConsAndData
{
   SCIP_CONS*            cons;                /**< pointer to the and-constraint of this 'term' of variables */
   SCIP_CONS*            origcons;            /**< pointer to the original and-constraint of this 'term' of variables
                                               *   only after problem was transformed, NULL otherwise */
   SCIP_VAR**            vars;                /**< all and-constraint variables */
   int                   nvars;               /**< number of all and-constraint variables */
   int                   svars;               /**< size for all and-constraint variables */
   SCIP_VAR**            newvars;             /**< new variables in this presolving round */
   int                   nnewvars;            /**< number of new variables in this presolving round */
   int                   snewvars;            /**< size of new variables in this presolving round */
   int                   noriguses;           /**< how often is this data in used by original constraints */
   int                   nuses;               /**< how often is this data in used by transformed constraints */
   unsigned int          istransformed:1;     /**< is transformed data active */
   unsigned int          isoriginal:1;        /**< is original data active */
};
typedef struct ConsAndData CONSANDDATA;

/** constraint data for pseudoboolean constraints */
struct SCIP_ConsData
{
   SCIP_Real             lhs;                /**< left hand side of constraint */
   SCIP_Real             rhs;                /**< right hand side of constraint */

   SCIP_CONS*            lincons;            /**< linear constraint which represents this pseudoboolean constraint */
   SCIP_LINEARCONSTYPE   linconstype;        /**< type of linear constraint which represents this pseudoboolean constraint */
   int                   nlinvars;           /**< number of linear variables (without and-resultants) */

   CONSANDDATA**         consanddatas;       /**< array of and-constraints-data-objects sorted after problem index of
                                              *   and-resultant of corresponding and-constraint */
   SCIP_Real*            andcoefs;           /**< array of coefficients for and-constraints of
                                              *   and-constraints-data-objects
                                              *   (changes during presolving, needs to be updated in every presolving
                                              *   round) */
   SCIP_Bool*            andnegs;            /**< array of negation status for and-constraints of
                                              *   and-constraints-data-objects
                                              *   (changes during presolving, needs to be updated in every presolving
                                              *   round) */
   int                   nconsanddatas;      /**< number of and-constraints-data-objects */
   int                   sconsanddatas;      /**< size of and-constraints-data-objects array */

   SCIP_VAR*             indvar;             /**< indicator variable if it's a soft constraint, or NULL */
   SCIP_Real             weight;             /**< weight of the soft constraint, if it is one */

   unsigned int          issoftcons:1;       /**< is this a soft constraint */
   unsigned int          changed:1;          /**< was constraint changed? */
   unsigned int          propagated:1;       /**< is constraint already propagated? */
   unsigned int          presolved:1;        /**< is constraint already presolved? */
   unsigned int          cliquesadded:1;     /**< were the cliques of the constraint already extracted? */
   unsigned int          upgradetried:1;     /**< was constraint upgrading already tried */
};

/** constraint handler data */
struct SCIP_ConshdlrData
{
   CONSANDDATA**         allconsanddatas;    /**< array of all and-constraint data objects inside the whole problem,
                                              *   created via this constraint handler */
   int                   nallconsanddatas;   /**< number of all and-constraint data objects inside the whole problem,
                                              *   created via this constraint handler */
   int                   sallconsanddatas;   /**< size of all and-constraint data objects inside the whole problem,
                                              *   created via this constraint handler */
   SCIP_HASHTABLE*       hashtable;          /**< hash table for all and-constraint data objects */
   int                   hashtablesize;      /**< size for hash table for all and-constraint data objects */

   SCIP_HASHMAP*         hashmap;            /**< hash map for mapping all resultant to and-constraint */
   int                   hashmapsize;        /**< size for hash map for mapping all resultant to and-constraint */

   SCIP_Bool             decomposenormalpbcons; /**< decompose every normal pseudo boolean constraint into a "linear" constraint and "and" constraints */
   SCIP_Bool             decomposeindicatorpbcons; /**< decompose every soft pseudo boolean constraint into "indicator" constraints and "and" constraints */
   SCIP_Bool             inithashmapandtable;/**< flag to store if the hashmap and -table is initialized */
   int                   nlinconss;          /**< for counting number of created linear constraints */
   int                   noriguses;          /**< how many consanddata objects are used by original constraints */
};


/*
 * Local methods
 */

/** comparison method for sorting and-resultants according to their problem index, which is used instead of the
 *  original index because the implicit resultants are shuffled when creating the constraints that otherwise results in
 *  shuffled problem copies,
 *  if an and-resultant is fixed, it will be put in front with respect to its original index
 *  if an and-resultant is negated, it will be put in front of its negation counterpart
 */
static
SCIP_DECL_SORTPTRCOMP(resvarComp)
{
   SCIP_VAR* var1 = elem1;
   SCIP_VAR* var2 = elem2;
   SCIP_Bool varneg1 = SCIPvarIsNegated(var1);
   SCIP_Bool varneg2 = SCIPvarIsNegated(var2);

   if( varneg1 )
      var1 = SCIPvarGetNegatedVar(var1);

   if( varneg2 )
      var2 = SCIPvarGetNegatedVar(var2);

   int varind1 = SCIPvarGetProbindex(var1);
   int varind2 = SCIPvarGetProbindex(var2);

   if( varind1 == -1 && varind2 == -1 )
   {
      varind1 = SCIPvarGetIndex(var1);
      varind2 = SCIPvarGetIndex(var2);
   }

   if( varind1 < varind2 )
      return -1;
   if( varind1 > varind2 )
      return +1;

   if( varneg1 && !varneg2 )
      return -1;
   if( !varneg1 && varneg2 )
      return +1;

   assert(elem1 == elem2);
   return 0;
}

/** comparison method for sorting consanddatas according to the problem index of their corresponding and-resultants,
 *  if a consanddata object is deleted, it is handled like it has an inactive resultant, so this will be put
 *  in front while sorting
 */
static
SCIP_DECL_SORTPTRCOMP(resvarCompWithInactive)
{
   CONSANDDATA* consanddata1 = (CONSANDDATA*)elem1;
   CONSANDDATA* consanddata2 = (CONSANDDATA*)elem2;

   assert(consanddata1 != NULL);
   assert(consanddata2 != NULL);

   /* consider that constraint data object can be only original */
   if( consanddata1->istransformed != consanddata2->istransformed )
      return consanddata1->istransformed ? +1 : -1;

   SCIP_CONS* consand1;
   SCIP_CONS* consand2;

   if( consanddata1->istransformed )
   {
      consand1 = consanddata1->cons;
      consand2 = consanddata2->cons;
   }
   else
   {
      consand1 = consanddata1->origcons;
      consand2 = consanddata2->origcons;
   }

   /* check if and-constraint is still active */
   if( SCIPconsIsDeleted(consand1) )
   {
      if( SCIPconsIsDeleted(consand2) )
         return 0;
      else
         return -1;
   }
   else if( SCIPconsIsDeleted(consand2) )
      return +1;

   /* hack with setting the scip pointer to NULL */
   return resvarComp((void*)SCIPgetResultantAnd(NULL, consand1), (void*)SCIPgetResultantAnd(NULL, consand2));
}

/** gets the key of the given element */
static
SCIP_DECL_HASHGETKEY(hashGetKeyAndConsDatas)
{  /*lint --e{715}*/
   /* the key is the element itself */
   return elem;
}

/** returns TRUE iff both keys are equal; two non-linear terms are equal if they have the same variables */
static
SCIP_DECL_HASHKEYEQ(hashKeyEqAndConsDatas)
{
#ifndef NDEBUG
   SCIP* scip;
#endif
   CONSANDDATA* cdata1;
   CONSANDDATA* cdata2;
   int v;

   cdata1 = (CONSANDDATA*)key1;
   cdata2 = (CONSANDDATA*)key2;

#ifndef NDEBUG
   scip = (SCIP*)userptr;
#endif
   assert(scip != NULL);
   assert(cdata1 != NULL);
   assert(cdata2 != NULL);
   assert(cdata1->vars != NULL);
   assert(cdata1->nvars > 1);
   assert(cdata2->vars != NULL);
   assert(cdata2->nvars > 1);

#ifndef NDEBUG
   /* check that cdata1 variables are sorted */
   for( v = cdata1->nvars - 1; v > 0; --v )
      assert(SCIPvarGetIndex(cdata1->vars[v]) >= SCIPvarGetIndex(cdata1->vars[v - 1]));
   /* check that cdata2 variables are sorted */
   for( v = cdata2->nvars - 1; v > 0; --v )
      assert(SCIPvarGetIndex(cdata2->vars[v]) >= SCIPvarGetIndex(cdata2->vars[v - 1]));
#endif

   /* checks trivial case */
   if( cdata1->nvars != cdata2->nvars )
      return FALSE;

   /* checks trivial case */
   if( cdata1->cons != NULL && cdata2->cons != NULL && cdata1->cons != cdata2->cons )
      return FALSE;

   /* check each variable in both cdatas for equality */
   for( v = cdata1->nvars - 1; v >= 0; --v )
   {
      assert(cdata1->vars[v] != NULL);
      assert(cdata2->vars[v] != NULL);

      /* tests if variables are equal */
      if( cdata1->vars[v] != cdata2->vars[v] )
      {
         assert(SCIPvarCompare(cdata1->vars[v], cdata2->vars[v]) == 1 ||
            SCIPvarCompare(cdata1->vars[v], cdata2->vars[v]) == -1);
         return FALSE;
      }
      assert(SCIPvarCompare(cdata1->vars[v], cdata2->vars[v]) == 0);
   }

   return TRUE;
}

/** returns the hash value of the key */
static
SCIP_DECL_HASHKEYVAL(hashKeyValAndConsDatas)
{  /*lint --e{715}*/
   CONSANDDATA* cdata;
   int minidx;
   int mididx;
   int maxidx;

   cdata = (CONSANDDATA*)key;

   assert(cdata != NULL);
   assert(cdata->vars != NULL);
   assert(cdata->nvars > 1);
#ifndef NDEBUG
   {
      /* check that these variables are sorted */
      int v;
      for( v = cdata->nvars - 1; v > 0; --v )
         assert(SCIPvarGetIndex(cdata->vars[v]) >= SCIPvarGetIndex(cdata->vars[v - 1]));
   }
#endif

   minidx = SCIPvarGetIndex(cdata->vars[0]);
   mididx = SCIPvarGetIndex(cdata->vars[cdata->nvars / 2]);
   maxidx = SCIPvarGetIndex(cdata->vars[cdata->nvars - 1]);
   assert(minidx >= 0 && minidx <= maxidx);

   return SCIPhashFour(cdata->nvars, minidx, mididx, maxidx);
}

/** initializes the hashmap and -table used in this constraint handler data for artificial variables and specific
 *  and-constraint data objects
 */
static
SCIP_RETCODE inithashmapandtable(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLRDATA**   conshdlrdata        /**< pointer to store the constraint handler data */
   )
{
   if( ((*conshdlrdata)->inithashmapandtable) )
   {
      assert((*conshdlrdata)->hashtable != NULL);
      assert((*conshdlrdata)->hashmap != NULL);

      return SCIP_OKAY;
   }

   assert((*conshdlrdata)->hashtable == NULL);
   assert((*conshdlrdata)->hashmap == NULL);

   /* create a hash table for and-constraint data objects */
   (*conshdlrdata)->hashtablesize = HASHSIZE_PSEUDOBOOLEANNONLINEARTERMS;
   SCIP_CALL( SCIPhashtableCreate(&((*conshdlrdata)->hashtable), SCIPblkmem(scip), (*conshdlrdata)->hashtablesize,
         hashGetKeyAndConsDatas, hashKeyEqAndConsDatas, hashKeyValAndConsDatas, (void*) scip) );

   /* create a hash table for and-resultant to and-constraint data objects */
   (*conshdlrdata)->hashmapsize = HASHSIZE_PSEUDOBOOLEANNONLINEARTERMS;
   SCIP_CALL( SCIPhashmapCreate(&((*conshdlrdata)->hashmap), SCIPblkmem(scip), (*conshdlrdata)->hashmapsize) );

   (*conshdlrdata)->inithashmapandtable = TRUE;

   return SCIP_OKAY;
}

/** creates constraint handler data for pseudo boolean constraint handler */
static
SCIP_RETCODE conshdlrdataCreate(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLRDATA**   conshdlrdata        /**< pointer to store the constraint handler data */
   )
{
   assert(scip != NULL);
   assert(conshdlrdata != NULL);

   SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );

   (*conshdlrdata)->allconsanddatas = NULL;
   (*conshdlrdata)->nallconsanddatas = 0;
   (*conshdlrdata)->sallconsanddatas = 10;

   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*conshdlrdata)->allconsanddatas), (*conshdlrdata)->sallconsanddatas ) );

   /* set hashmap and -table to NULL, mark them as uninitialized */
   (*conshdlrdata)->inithashmapandtable = FALSE;
   (*conshdlrdata)->hashtable = NULL;
   (*conshdlrdata)->hashtablesize = 0;
   (*conshdlrdata)->hashmap = NULL;
   (*conshdlrdata)->hashmapsize = 0;

   /* for constraint names count number of created constraints */
   (*conshdlrdata)->nlinconss = 0;

   /* initializes how many consanddata objects are used by original constraints */
   (*conshdlrdata)->noriguses = 0;

   return SCIP_OKAY;
}


/** frees constraint handler data for pseudo boolean constraint handler */
static
SCIP_RETCODE conshdlrdataFree(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLRDATA**   conshdlrdata        /**< pointer to the constraint handler data */
   )
{
   assert(scip != NULL);
   assert(conshdlrdata != NULL);
   assert(*conshdlrdata != NULL);
   assert((*conshdlrdata)->nallconsanddatas == 0);

   /* free hash table if necessary */
   if( (*conshdlrdata)->inithashmapandtable )
   {
      SCIPhashmapFree(&((*conshdlrdata)->hashmap));
      (*conshdlrdata)->hashmapsize = 0;
      SCIPhashtableFree(&((*conshdlrdata)->hashtable));
      (*conshdlrdata)->hashtablesize = 0;
   }
   else
   {
      assert((*conshdlrdata)->hashmap == NULL);
      assert((*conshdlrdata)->hashtable == NULL);
   }
   (*conshdlrdata)->inithashmapandtable = FALSE;

   /* clear array for all consanddata objects */
   SCIPfreeBlockMemoryArray(scip, &((*conshdlrdata)->allconsanddatas), (*conshdlrdata)->sallconsanddatas );

   (*conshdlrdata)->allconsanddatas = NULL;
   (*conshdlrdata)->nallconsanddatas = 0;
   (*conshdlrdata)->sallconsanddatas = 0;

   SCIPfreeBlockMemory(scip, conshdlrdata);

   return SCIP_OKAY;
}

/** gets number of variables in linear constraint */
static
SCIP_RETCODE getLinearConsNVars(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< linear constraint */
   SCIP_LINEARCONSTYPE const constype,       /**< linear constraint type */
   int*const             nvars               /**< pointer to store number variables of linear constraint */
   )
{
   assert(scip != NULL);
   assert(cons != NULL);
   assert(nvars != NULL);

   /* determine for each special linear constranit all variables and coefficients */
   switch( constype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      *nvars = SCIPgetNVarsLinear(scip, cons);
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
      *nvars = SCIPgetNVarsLogicor(scip, cons);
      break;
   case SCIP_LINEARCONSTYPE_KNAPSACK:
      *nvars = SCIPgetNVarsKnapsack(scip, cons);
      break;
   case SCIP_LINEARCONSTYPE_SETPPC:
      *nvars = SCIPgetNVarsSetppc(scip, cons);
      break;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
      *nvars = SCIPgetNVarsEQKnapsack(scip, cons);
      break;
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   return SCIP_OKAY;
}


/** gets sides of linear constraint */
static
SCIP_RETCODE getLinearConsSides(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< linear constraint */
   SCIP_LINEARCONSTYPE const constype,       /**< linear constraint type */
   SCIP_Real*const       lhs,                /**< pointer to store left hand side of linear constraint */
   SCIP_Real*const       rhs                 /**< pointer to store right hand side of linear constraint */
   )
{
   SCIP_SETPPCTYPE type;

   switch( constype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      *lhs = SCIPgetLhsLinear(scip, cons);
      *rhs = SCIPgetRhsLinear(scip, cons);
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
      *lhs = 1.0;
      *rhs = SCIPinfinity(scip);
      break;
   case SCIP_LINEARCONSTYPE_KNAPSACK:
      *lhs = -SCIPinfinity(scip);
      *rhs = SCIPgetCapacityKnapsack(scip, cons);
      break;
   case SCIP_LINEARCONSTYPE_SETPPC:
      type = SCIPgetTypeSetppc(scip, cons);

      switch( type )
      {
      case SCIP_SETPPCTYPE_PARTITIONING:
         *lhs = 1.0;
         *rhs = 1.0;
         break;
      case SCIP_SETPPCTYPE_PACKING:
         *lhs = -SCIPinfinity(scip);
         *rhs = 1.0;
         break;
      case SCIP_SETPPCTYPE_COVERING:
         *lhs = 1.0;
         *rhs = SCIPinfinity(scip);
         break;
      default:
         SCIPerrorMessage("unknown setppc type\n");
         return SCIP_INVALIDDATA;
      }
      break;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
      *lhs = SCIPgetCapacityEQKnapsack(scip, cons);
      *rhs = *lhs;
      break;
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   return SCIP_OKAY;
}

/** gets variables and coefficients of linear constraint */
static
SCIP_RETCODE getLinearConsVarsData(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< linear constraint */
   SCIP_LINEARCONSTYPE const constype,       /**< linear constraint type */
   SCIP_VAR**const       vars,               /**< array to store variables of linear constraint */
   SCIP_Real*const       coefs,              /**< array to store coefficient of linear constraint, or NULL */
   int*const             nvars               /**< pointer to store number variables of linear constraint */
   )
{
   SCIP_VAR** linvars;
   int v;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(vars != NULL);
   assert(nvars != NULL);

   /* determine for each special linear constrait all variables and coefficients */
   switch( constype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
   {
      SCIP_Real* lincoefs;

      *nvars = SCIPgetNVarsLinear(scip, cons);
      linvars = SCIPgetVarsLinear(scip, cons);

      if( coefs != NULL )
      {
         lincoefs = SCIPgetValsLinear(scip, cons);

         for( v = 0; v < *nvars; ++v )
         {
            vars[v] = linvars[v];
            coefs[v] = lincoefs[v];
         }
      }
      else
      {
         for( v = 0; v < *nvars; ++v )
            vars[v] = linvars[v];
      }

      break;
   }
   case SCIP_LINEARCONSTYPE_LOGICOR:
      *nvars = SCIPgetNVarsLogicor(scip, cons);
      linvars = SCIPgetVarsLogicor(scip, cons);
      assert( linvars != NULL );

      if( coefs != NULL )
      {
         for( v = 0; v < *nvars; ++v )
         {
            vars[v] = linvars[v];
            coefs[v] = 1.0;
         }
      }
      else
      {
         for( v = 0; v < *nvars; ++v )
            vars[v] = linvars[v];
      }

      break;
   case SCIP_LINEARCONSTYPE_KNAPSACK:
   {
      SCIP_Longint* weights;

      *nvars = SCIPgetNVarsKnapsack(scip, cons);
      linvars = SCIPgetVarsKnapsack(scip, cons);
      assert( linvars != NULL );

      if( coefs != NULL )
      {
         weights = SCIPgetWeightsKnapsack(scip, cons);

         for( v = 0; v < *nvars; ++v )
         {
            vars[v] = linvars[v];
            coefs[v] = (SCIP_Real) weights[v];
         }
      }
      else
      {
         for( v = 0; v < *nvars; ++v )
            vars[v] = linvars[v];
      }

      break;
   }
   case SCIP_LINEARCONSTYPE_SETPPC:
      *nvars = SCIPgetNVarsSetppc(scip, cons);
      linvars = SCIPgetVarsSetppc(scip, cons);
      assert( linvars != NULL );

      if( coefs != NULL )
      {
         for( v = 0; v < *nvars; ++v )
         {
            vars[v] = linvars[v];
            coefs[v] = 1.0;
         }
      }
      else
      {
         for( v = 0; v < *nvars; ++v )
            vars[v] = linvars[v];
      }

      break;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
   {
      SCIP_Longint* weights;

      *nvars = SCIPgetNVarsEQKnapsack(scip, cons);
      linvars = SCIPgetVarsEQKnapsack(scip, cons);
      assert( linvars != NULL );

      if( coefs != NULL )
      {
         weights = SCIPgetWeightsEQKnapsack(scip, cons);

         for( v = 0; v < *nvars; ++v )
         {
            vars[v] = linvars[v];
            coefs[v] = (SCIP_Real) weights[v];
         }
      }
      else
      {
         for( v = 0; v < *nvars; ++v )
            vars[v] = linvars[v];
      }

      break;
   }
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   return SCIP_OKAY;
}

/** splits up into original linear variables and artificial and-resultants */
static
SCIP_RETCODE getLinVarsAndAndRess(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_VAR**const       vars,               /**< all variables of linear constraint */
   SCIP_Real*const       coefs,              /**< all coefficients of linear constraint, or NULL */
   int const             nvars,              /**< number of all variables of linear constraint */
   SCIP_VAR**const       linvars,            /**< array to store not and-resultant variables of linear constraint, or NULL */
   SCIP_Real*const       lincoefs,           /**< array to store coefficients of not and-resultant variables of linear
                                              *   constraint, or NULL */
   int*const             nlinvars,           /**< pointer to store number of not and-resultant variables, or NULL */
   SCIP_VAR**const       andress,            /**< array to store and-resultant variables of linear constraint, or NULL */
   SCIP_Real*const       andcoefs,           /**< array to store coefficients of and-resultant variables of linear
                                              *   constraint, or NULL */
   SCIP_Bool*const       andnegs,            /**< array to store negation status of and-resultant variables of linear
                                              *   constraint, or NULL */
   int*const             nandress            /**< pointer to store number of and-resultant variables, or NULL */
   )
{
   SCIP_CONSHDLR* conshdlr;
   SCIP_CONSHDLRDATA* conshdlrdata;
   int v;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(vars != NULL);
   assert((linvars != NULL) == (nlinvars != NULL));
   assert((andress == NULL) || (nandress != NULL));
   assert((andcoefs != NULL) == (andnegs != NULL));
   assert((coefs != NULL) == ((lincoefs != NULL) || (andcoefs != NULL)));
   assert(linvars != NULL || andress != NULL);

   if( nlinvars != NULL )
      *nlinvars = 0;
   if( nandress != NULL )
      *nandress = 0;

   conshdlr = SCIPconsGetHdlr(cons);
   assert(conshdlr != NULL);
   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);
   assert(conshdlrdata->hashmap != NULL);

   /* split variables into original and artificial variables */
   for( v = 0; v < nvars; ++v )
   {
      SCIP_Bool hashmapentryexists;
      SCIP_VAR* hashmapvar;

      assert(vars[v] != NULL);

      hashmapentryexists = SCIPhashmapExists(conshdlrdata->hashmap, (void*)(vars[v]));

      if( !hashmapentryexists && SCIPvarIsNegated(vars[v]) )
      {
         hashmapvar = SCIPvarGetNegationVar(vars[v]);
         hashmapentryexists = SCIPhashmapExists(conshdlrdata->hashmap, (void*)(hashmapvar));
      }
      else
         hashmapvar = vars[v];

      /* if and resultant is not a resultant anymore (meaning the corresponding and-constraint was deleted/upgraded),
       * correct the flag and count this variable as normal linear variable
       */
      if( hashmapentryexists )
      {
         if( !SCIPconsIsOriginal(cons) )
         {
            CONSANDDATA* consanddata = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)(hashmapvar));
            assert(consanddata != NULL);

            hashmapentryexists = (consanddata->istransformed);

            if( hashmapentryexists )
            {
               assert(consanddata->cons != NULL);
               hashmapentryexists = !SCIPconsIsDeleted(consanddata->cons);
            }
         }
      }

      if( !hashmapentryexists && linvars != NULL && nlinvars != NULL )
      {
         linvars[*nlinvars] = vars[v];
         if( lincoefs != NULL )
         {
            assert(coefs != NULL);
            lincoefs[*nlinvars] = coefs[v];
         }
         ++(*nlinvars);
      }
      else if( hashmapentryexists && nandress != NULL )
      {
         if( andress != NULL )
         {
            andress[*nandress] = hashmapvar;

            if( andcoefs != NULL )
            {
               assert(andnegs != NULL);
               assert(coefs != NULL);
               andcoefs[*nandress] = coefs[v];
               andnegs[*nandress] = (vars[v] != hashmapvar);
            }
         }
         ++(*nandress);
      }
   }

   return SCIP_OKAY;
}


#ifdef CHECK_CONSISTENCY
/** check constraint consistency */
static
void checkConsConsistency(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< pseudoboolean constraint */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_VAR** vars;
   SCIP_Real* coefs;
   int nvars;
   SCIP_VAR** linvars;
   SCIP_Real* lincoefs;
   int nlinvars;
   SCIP_VAR** andress;
   SCIP_Real* andcoefs;
   SCIP_Bool* andnegs;
   int nandress;
   SCIP_Bool* alreadyfound;
   SCIP_VAR* res;
   int c;
   int v;
   SCIP_Real newlhs;
   SCIP_Real newrhs;

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

   if( SCIPgetStage(scip) == SCIP_STAGE_FREETRANS )
      return;

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   /* check standard pointers and sizes */
   assert(consdata->lincons != NULL);
   assert(!SCIPconsIsDeleted(consdata->lincons));
   assert(consdata->linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
   assert(consdata->consanddatas != NULL);
   assert(consdata->nconsanddatas > 0);
   assert(consdata->nconsanddatas <= consdata->sconsanddatas);

   /* get sides of linear constraint */
   SCIP_CALL_ABORT( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &newlhs, &newrhs) );
   assert(!SCIPisInfinity(scip, newlhs));
   assert(!SCIPisInfinity(scip, -newrhs));
   assert(SCIPisLE(scip, newlhs, newrhs));
   assert(SCIPisEQ(scip, newrhs, consdata->rhs) || SCIPisEQ(scip, newrhs, -consdata->lhs));
   assert(SCIPisEQ(scip, newlhs, consdata->lhs) || SCIPisEQ(scip, newlhs, -consdata->rhs));

   /* check number of linear variables */
   SCIP_CALL_ABORT( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
   assert(nvars == consdata->nlinvars + consdata->nconsanddatas);

   /* get temporary memory */
   SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &coefs, nvars) );
   SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &linvars, nvars) );
   SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &lincoefs, nvars) );
   SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &andress, nvars) );
   SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &andcoefs, nvars) );
   SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &andnegs, nvars) );
   SCIP_CALL_ABORT( SCIPallocClearBufferArray(scip, &alreadyfound, nvars) );

   /* get variables and coefficients */
   SCIP_CALL_ABORT( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
   assert(coefs != NULL || nvars == 0);

   /* calculate all not artificial linear variables and all artificial and-resultants */
   SCIP_CALL_ABORT( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars,
         andress, andcoefs, andnegs, &nandress) );
   assert(nlinvars == consdata->nlinvars);
   assert(nandress == consdata->nconsanddatas);

   for( v = nandress - 1; v >= 0; --v )
   {
      SCIP_VAR* andresultant = andress[v];
      int nfound = 0;

      for( c = consdata->nconsanddatas - 1; c >= 0; --c )
      {
         assert(consdata->consanddatas[c] != NULL);
         if( consdata->consanddatas[c]->cons != NULL )
         {
            res = SCIPgetResultantAnd(scip, consdata->consanddatas[c]->cons);
            assert(res != NULL);

            if( res == andresultant && consdata->andnegs[c] == andnegs[v] && consdata->andcoefs[c] == andcoefs[v] )
            {
               /* resultant should be either active or a negated variable of an active one */
               assert(SCIPvarIsActive(res) || (SCIPvarIsNegated(res) && SCIPvarIsActive(SCIPvarGetNegationVar(res))));
               assert(!alreadyfound[c]);

               /* all and-resultants should be merged, so it is only allowed that each variable exists one time */
               alreadyfound[c] = TRUE;
               ++nfound;
               break;
            }
         }
      }
      assert(nfound == 1);
   }

   for( c = consdata->nconsanddatas - 1; c >= 0; --c )
   {
      assert(alreadyfound[c]);
   }

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &alreadyfound);
   SCIPfreeBufferArray(scip, &andnegs);
   SCIPfreeBufferArray(scip, &andcoefs);
   SCIPfreeBufferArray(scip, &andress);
   SCIPfreeBufferArray(scip, &lincoefs);
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &coefs);
   SCIPfreeBufferArray(scip, &vars);
}
#else
#define checkConsConsistency(scip, cons) /**/
#endif


/** transforming transformed consanddata object back to original space, if an corresponding original constraint exists,
 *  also clearing all transformed data, i.e. releasing transformed variables
 */
static
SCIP_RETCODE transformToOrig(
   SCIP*const            scip,               /**< SCIP data structure */
   CONSANDDATA*          consanddata,        /**< consanddata object */
   SCIP_CONSHDLRDATA*    conshdlrdata        /**< constraint handler data */
   )
{
   SCIP_VAR** tmpvars;
   SCIP_Bool origdata;
   int ntmpvars;
   int v;

   assert(scip != NULL);
   assert(consanddata != NULL);
   assert(conshdlrdata != NULL);

   origdata = TRUE;

   tmpvars = consanddata->vars;
   ntmpvars = consanddata->nvars;

   /* release all transformed variables */
   for( v = ntmpvars - 1; v >= 0; --v )
   {
      assert(tmpvars[v] != NULL);
      if( SCIPvarIsTransformed(tmpvars[v]) )
      {
         SCIP_CALL( SCIPreleaseVar(scip, &tmpvars[v]) );
         origdata = FALSE;
      }
   }

   tmpvars = consanddata->newvars;
   ntmpvars = consanddata->nnewvars;

   /* release all variables */
   for( v = ntmpvars - 1; v >= 0; --v )
   {
      assert(tmpvars[v] != NULL);
      if( SCIPvarIsTransformed(tmpvars[v]) )
      {
         SCIP_CALL( SCIPreleaseVar(scip, &tmpvars[v]) );
         origdata = FALSE;
      }
   }

   /* reinstall original data */
   if( !origdata || consanddata->nvars == 0 )
   {
      SCIPfreeBlockMemoryArrayNull(scip, &(consanddata->vars), consanddata->svars);
      SCIPfreeBlockMemoryArrayNull(scip, &(consanddata->newvars), consanddata->snewvars);

      consanddata->nuses = 0;
      consanddata->nvars = 0;
      consanddata->svars = 0;
      consanddata->nnewvars = 0;
      consanddata->snewvars = 0;
      consanddata->istransformed = FALSE;

      if( consanddata->noriguses > 0 )
      {
         assert(consanddata->origcons != NULL);
         assert(consanddata->isoriginal);

         assert(SCIPgetNVarsAnd(scip, consanddata->origcons) > 0);
         assert(SCIPgetVarsAnd(scip, consanddata->origcons) != NULL);
         consanddata->nvars = SCIPgetNVarsAnd(scip, consanddata->origcons);
         consanddata->svars = consanddata->nvars;

         if( consanddata->nvars > 0 )
         {
            SCIP_VAR** andvars = SCIPgetVarsAnd(scip, consanddata->origcons);

            SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(consanddata->vars), andvars, consanddata->nvars) );

            /* sort variables */
            SCIPsortPtr((void**)(consanddata->vars), SCIPvarComp, consanddata->nvars);
         }

         /* check that the hash map and tabkle are still having all information */
         if( conshdlrdata->inithashmapandtable )
         {
            assert(conshdlrdata->hashmap != NULL);
            assert(conshdlrdata->hashtable != NULL);
            assert(SCIPgetResultantAnd(scip, consanddata->origcons) != NULL);
            assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
            assert(consanddata == (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)consanddata)));
            assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons)));
            assert(consanddata == (CONSANDDATA*)(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons))));
         }
      }
      else
         assert(consanddata->origcons == NULL);
   }
   else
   {
      assert(consanddata->nuses == 0);
      assert(consanddata->nnewvars == 0);
      assert(consanddata->snewvars == 0);
      assert(consanddata->newvars == NULL);

      consanddata->istransformed = FALSE;

      if( consanddata->noriguses > 0 )
      {
         assert(consanddata->origcons != NULL);
         assert(consanddata->nvars > 0);
         assert(consanddata->svars > 0);
         assert(consanddata->vars != NULL);
         assert(consanddata->isoriginal);

         /* check that the hash map and tabkle are still having all information */
         if( conshdlrdata->inithashmapandtable )
         {
            assert(conshdlrdata->hashmap != NULL);
            assert(conshdlrdata->hashtable != NULL);
            assert(SCIPgetResultantAnd(scip, consanddata->origcons) != NULL);
            assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
            assert(consanddata == (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)consanddata)));
            assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons)));
            assert(consanddata == (CONSANDDATA*)(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons))));
         }
      }
   }

   return SCIP_OKAY;
}



/** creates a pseudo boolean constraint data */
static
SCIP_RETCODE consdataCreate(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLR*const   conshdlr,           /**< pseudoboolean constraint handler */
   SCIP_CONSDATA**       consdata,           /**< pointer to linear constraint data */
   SCIP_CONS*const       lincons,            /**< linear constraint with artificial and-resultants representing this pseudoboolean constraint */
   SCIP_LINEARCONSTYPE const linconstype,    /**< type of linear constraint */
   SCIP_CONS**const      andconss,           /**< array of and-constraints which occur in this pseudoboolean constraint */
   SCIP_Real*const       andcoefs,           /**< coefficients of and-constraints */
   SCIP_Bool*const       andnegs,            /**< negation status of and-constraints (or NULL, if no negated resultants) */
   int const             nandconss,          /**< number of and-constraints */
   SCIP_VAR*const        indvar,             /**< indicator variable if it's a soft constraint, or NULL */
   SCIP_Real const       weight,             /**< weight of the soft constraint, if it is one */
   SCIP_Bool const       issoftcons,         /**< is this a soft constraint */
   SCIP_Real             lhs,                /**< left hand side of row */
   SCIP_Real             rhs,                /**< right hand side of row */
   SCIP_Bool             check,              /**< is the new constraint a check constraint? */
   SCIP_Bool             transforming        /**< are we called by CONSTRANS */
   )
{
   SCIP_Bool transformed;
   int nvars;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(consdata != NULL);
   assert(lincons != NULL && linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
   assert(andconss != NULL || nandconss == 0);
   assert(andcoefs != NULL || nandconss == 0);
   assert(!issoftcons || (!SCIPisZero(scip, weight) && indvar != NULL));

   /* adjust right hand side */
   if( SCIPisInfinity(scip, rhs) )
      rhs = SCIPinfinity(scip);
   else if( SCIPisInfinity(scip, -rhs) )
      rhs = -SCIPinfinity(scip);

   /* adjust left hand side */
   if( SCIPisInfinity(scip, -lhs) )
      lhs = -SCIPinfinity(scip);
   else if( SCIPisInfinity(scip, lhs) )
      lhs = SCIPinfinity(scip);

   /* check left and right side */
   if( SCIPisGT(scip, lhs, rhs) )
   {
      SCIPerrorMessage("left hand side of pseudo boolean constraint greater than right hand side\n");
      SCIPerrorMessage(" -> lhs=%g, rhs=%g\n", lhs, rhs);
      return SCIP_INVALIDDATA;
   }

   transformed = SCIPisTransformed(scip);

   /* allocate memory for the constraint data */
   SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );

   /* initialize the weights for soft constraints */
   (*consdata)->issoftcons = issoftcons;
   if( issoftcons )
   {
      (*consdata)->weight = weight;
      if( transformed )
      {
         SCIP_CALL( SCIPgetTransformedVar(scip, indvar, &((*consdata)->indvar)) );
      }
      else
         (*consdata)->indvar = indvar;
   }
   else
      (*consdata)->indvar = NULL;

   /* copy linear constraint */
   (*consdata)->lincons = lincons;
   (*consdata)->linconstype = linconstype;

   /* get transformed linear constraint and capture it if necessary */
   if( transforming )
   {
      /* do not capture the and constraint when scip is in transformed mode; this automatically happens in
       * SCIPtransformCons()
       */
      SCIP_CALL( SCIPtransformCons(scip, (*consdata)->lincons, &((*consdata)->lincons)) );
      assert((*consdata)->lincons != NULL);
   }

   if( transforming || transformed )
   {
      assert(SCIPconsIsTransformed((*consdata)->lincons));

      /* we want to check all necessary transformed linear constraints */
      SCIP_CALL( SCIPsetConsChecked(scip, (*consdata)->lincons, check) );
   }

   /* get number of non-linear terms in pseudoboolean constraint */
   SCIP_CALL( getLinearConsNVars(scip, (*consdata)->lincons, (*consdata)->linconstype, &nvars) );
   (*consdata)->nlinvars = nvars - nandconss;

   /* copy and-constraints */
   if( nandconss > 0 )
   {
      SCIP_CONSHDLRDATA* conshdlrdata;
      SCIP_VAR** andress;
      int c;

      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*consdata)->consanddatas), nandconss) );
      SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &((*consdata)->andcoefs), andcoefs, nandconss) );
      if( andnegs != NULL )
      {
         SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &((*consdata)->andnegs), andnegs, nandconss) );
      }
      else
      {
         SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &((*consdata)->andnegs), nandconss) );
      }
      (*consdata)->nconsanddatas = nandconss;
      (*consdata)->sconsanddatas = nandconss;

      /* allocate temporary memory */
      SCIP_CALL( SCIPallocBufferArray(scip, &andress, nandconss) );

      conshdlrdata = SCIPconshdlrGetData(conshdlr);
      assert(conshdlrdata != NULL);
      assert(conshdlrdata->hashmap != NULL);

      /* get all and-resultants for sorting */
      for( c = nandconss - 1; c >= 0; --c )
      {
         assert(andconss[c] != NULL);

         andress[c] = SCIPgetResultantAnd(scip, andconss[c]);
         assert(andress[c] != NULL);

         (*consdata)->consanddatas[c] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)andress[c]);
         assert((*consdata)->consanddatas[c] != NULL);
         assert((*consdata)->consanddatas[c]->origcons == andconss[c] || (*consdata)->consanddatas[c]->cons == andconss[c]);

         if( transforming )
         {
            /* if we perform a new transformation, we need to capture the transformed constraint */
            if( (*consdata)->consanddatas[c]->origcons != NULL && (*consdata)->consanddatas[c]->cons == NULL )
            {
               SCIP_VAR** vars;
               int ncvars;
               int v;

               /* do not capture the and constraint when scip is in transformed mode; this automatically happens in
                * SCIPtransformCons()
                */
               SCIP_CALL( SCIPtransformCons(scip, (*consdata)->consanddatas[c]->origcons, &((*consdata)->consanddatas[c]->cons)) );
               assert((*consdata)->consanddatas[c]->cons != NULL);
               assert((*consdata)->consanddatas[c]->newvars == NULL);
               assert((*consdata)->consanddatas[c]->isoriginal);

               (*consdata)->consanddatas[c]->istransformed = TRUE;

               /* lock upgrade to keep control */
               SCIPconsAddUpgradeLocks((*consdata)->consanddatas[c]->cons, +1);

               vars = (*consdata)->consanddatas[c]->vars;
               ncvars = (*consdata)->consanddatas[c]->nvars;
               assert(vars != NULL || ncvars == 0);

               /* get transformed variables */
               SCIP_CALL( SCIPgetTransformedVars(scip, ncvars, vars, vars) );

               /* resort variables in transformed problem, because the order might change while tranforming */
               SCIPsortPtr((void**)vars, SCIPvarComp, ncvars);

               /* capture all transformed variables */
               for( v = ncvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPcaptureVar(scip, vars[v]) ); /*lint !e613*/
               }
            }
            else if( (*consdata)->consanddatas[c]->cons != NULL )
               assert((*consdata)->consanddatas[c]->istransformed);

            ++((*consdata)->consanddatas[c]->nuses);
         }
         else if( transformed )
         {
            assert((*consdata)->consanddatas[c]->cons == andconss[c]);
            assert(SCIPconsIsTransformed(andconss[c]));
            assert((*consdata)->consanddatas[c]->istransformed);
         }
      }

      /* sort and-constraints after problem indices of corresponding and-resultants */
      SCIPsortPtrPtrRealBool((void**)andress, (void**)((*consdata)->consanddatas), (*consdata)->andcoefs, (*consdata)->andnegs, resvarComp, nandconss);

      /* free temporary memory */
      SCIPfreeBufferArray(scip, &andress);
   }
   else
   {
      (*consdata)->consanddatas = NULL;
      (*consdata)->andcoefs = NULL;
      (*consdata)->andnegs = NULL;
      (*consdata)->nconsanddatas = 0;
      (*consdata)->sconsanddatas = 0;
   }

   /* copy left and right hand side */
   (*consdata)->lhs = lhs;
   (*consdata)->rhs = rhs;

   (*consdata)->changed = TRUE;
   (*consdata)->propagated = FALSE;
   (*consdata)->presolved = FALSE;
   (*consdata)->cliquesadded = FALSE;
   (*consdata)->upgradetried = TRUE;

   /* count number of used consanddata objects in original problem */
   if( SCIPgetStage(scip) == SCIP_STAGE_PROBLEM )
   {
      SCIP_CONSHDLRDATA* conshdlrdata;
      conshdlrdata = SCIPconshdlrGetData(conshdlr);
      assert(conshdlrdata != NULL);

      conshdlrdata->noriguses += (*consdata)->nconsanddatas;
   }

   return SCIP_OKAY;
}

/** free a pseudo boolean constraint data */
static
SCIP_RETCODE consdataFree(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSDATA**       consdata,           /**< pointer to linear constraint data */
   SCIP_Bool             isorig,             /**< are we freeing an original constraint? */
   SCIP_CONSHDLRDATA*    conshdlrdata        /**< constraint handler data */
   )
{
   CONSANDDATA** consanddatas;
   int nconsanddatas;
   int c;

   assert(scip != NULL);
   assert(consdata != NULL);
   assert(*consdata != NULL);
   assert((*consdata)->consanddatas != NULL || (*consdata)->nconsanddatas == 0);
   assert(conshdlrdata != NULL);

   /* release linear constraint */
   if( (*consdata)->lincons != NULL )
   {
      SCIP_CALL( SCIPreleaseCons(scip, &((*consdata)->lincons)) );
   }

   nconsanddatas = (*consdata)->nconsanddatas;
   consanddatas = (*consdata)->consanddatas;

   /* count down uses and if necessary release constraints and delete data from hashtable and -map */
   for( c = nconsanddatas - 1; c >= 0; --c )
   {
      assert((consanddatas[c]->origcons == NULL) == (consanddatas[c]->noriguses == 0));
      assert((consanddatas[c]->cons == NULL) == (consanddatas[c]->nuses == 0));
      assert(consanddatas[c]->nuses >= 0);
      assert(consanddatas[c]->noriguses >= 0);
      assert(isorig ? consanddatas[c]->cons == NULL : TRUE);

      /* are we deleteing a transformed constraint */
      if( !isorig && consanddatas[c]->cons != NULL )
      {
         assert(!SCIPconsIsOriginal(consanddatas[c]->cons));

         --(consanddatas[c]->nuses);

         /* if the consanddata is not used anymore, release the constraint and clear the hashmap- and table */
         if( consanddatas[c]->nuses == 0 )
         {
            if( conshdlrdata->inithashmapandtable )
            {
               assert(conshdlrdata->hashmap != NULL);
               assert(conshdlrdata->hashtable != NULL);

               /* remove consanddata from hashtable, if it existed only in transformed space */
               if( consanddatas[c]->origcons == NULL )
               {
                  assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddatas[c]));
                  SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddatas[c]) );
               }
               assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->cons)));
               SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->cons)) );
            }

            /* unlock upgrade to provide control */
            SCIPconsAddUpgradeLocks(consanddatas[c]->cons, -1);

            /* release and-constraint */
            SCIP_CALL( SCIPreleaseCons(scip, &consanddatas[c]->cons) );

            /* if the consanddata object was only used in transformed space, delete the memory block */
            if( consanddatas[c]->origcons == NULL )
            {
               int d;

               assert(conshdlrdata->nallconsanddatas > 0);

               for( d = conshdlrdata->nallconsanddatas - 1; d >= 0; --d )
               {
                  if( conshdlrdata->allconsanddatas[d] == consanddatas[c] )
                  {
                     --conshdlrdata->nallconsanddatas;

                     SCIPfreeBlockMemory(scip, &(conshdlrdata->allconsanddatas[d])); /*lint !e866*/

                     conshdlrdata->allconsanddatas[d] = conshdlrdata->allconsanddatas[conshdlrdata->nallconsanddatas];
                     break;
                  }
               }
               assert(d >= 0);
               continue;
            }
         }
      }
      /* are we deleteing an original constraint */
      else if( isorig && consanddatas[c]->origcons != NULL )
      {
         assert(SCIPconsIsOriginal(consanddatas[c]->origcons));
         assert(consanddatas[c]->nuses == 0);
         assert(consanddatas[c]->nnewvars == 0);
         assert(consanddatas[c]->snewvars == 0);
         assert(consanddatas[c]->newvars == NULL);

         --(consanddatas[c]->noriguses);

         /* if the consanddata is not used anymore, release the constraint and clear the hashmap- and table */
         if( consanddatas[c]->noriguses == 0 )
         {
            int d;

            if( conshdlrdata->inithashmapandtable )
            {
               assert(conshdlrdata->hashmap != NULL);
               assert(conshdlrdata->hashtable != NULL);

               assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddatas[c]));
               SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddatas[c]) );

               assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons)));
               SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons)) );
            }

            if( consanddatas[c]->vars != NULL )
            {
               assert(consanddatas[c]->nvars > 0);
               assert(consanddatas[c]->svars > 0);
               assert(consanddatas[c]->svars >= consanddatas[c]->nvars);

               SCIPfreeBlockMemoryArrayNull(scip, &(consanddatas[c]->vars), consanddatas[c]->svars);
               consanddatas[c]->nvars = 0;
               consanddatas[c]->svars = 0;
            }
            else
            {
               assert(consanddatas[c]->nvars == 0);
               assert(consanddatas[c]->svars == 0);
            }

            /* release original and-constraint */
            SCIP_CALL( SCIPreleaseCons(scip, &consanddatas[c]->origcons) );
            assert(consanddatas[c]->origcons == NULL);

            /* delete consanddata object */
            assert(conshdlrdata->nallconsanddatas > 0);
            for( d = conshdlrdata->nallconsanddatas - 1; d >= 0; --d )
            {
               if( conshdlrdata->allconsanddatas[d] == consanddatas[c] )
               {
                  --conshdlrdata->nallconsanddatas;

                  SCIPfreeBlockMemory(scip, &(conshdlrdata->allconsanddatas[d])); /*lint !e866*/

                  conshdlrdata->allconsanddatas[d] = conshdlrdata->allconsanddatas[conshdlrdata->nallconsanddatas];
                  break;
               }
            }
            assert(d >= 0);

            continue;
         }
      }
      else
      {
         assert(!consanddatas[c]->istransformed);
         assert(consanddatas[c]->cons == NULL);
      }

      /* clear and remove capture of transformed consanddata */
      if( consanddatas[c]->nuses == 0 && consanddatas[c]->istransformed )
      {
         SCIP_CALL( transformToOrig(scip, consanddatas[c], conshdlrdata) );
      }
#ifndef NDEBUG
      else if( consanddatas[c]->nuses == 0 )
      {
         SCIP_VAR** tmpvars;
         int ntmpvars;
         int v;

         assert(consanddatas[c]->nnewvars == 0);
         assert(consanddatas[c]->snewvars == 0);
         assert(consanddatas[c]->newvars == NULL);

         tmpvars = consanddatas[c]->vars;
         ntmpvars = consanddatas[c]->nvars;

         /* release all variables */
         for( v = ntmpvars - 1; v >= 0; --v )
         {
            assert(tmpvars[v] != NULL);
            assert(SCIPvarIsOriginal(tmpvars[v]));
         }
      }
#endif

      /* restore original data */
      if( !consanddatas[c]->istransformed && consanddatas[c]->noriguses > 0 )
      {
         assert(consanddatas[c]->origcons != NULL);
         assert(consanddatas[c]->nuses == 0);
         assert(consanddatas[c]->nnewvars == 0);
         assert(consanddatas[c]->snewvars == 0);
         assert(consanddatas[c]->newvars == NULL);
         assert(consanddatas[c]->nvars > 0);
         assert(consanddatas[c]->svars > 0);
         assert(consanddatas[c]->svars >= consanddatas[c]->nvars);
         assert(consanddatas[c]->vars != NULL);
         assert(consanddatas[c]->isoriginal);

         assert(consanddatas[c]->nvars == SCIPgetNVarsAnd(scip, consanddatas[c]->origcons));
         assert(SCIPgetVarsAnd(scip, consanddatas[c]->origcons) != NULL);

         /* check that the hash map and tabkle are still having all information */
         if( conshdlrdata->inithashmapandtable )
         {
            assert(conshdlrdata->hashmap != NULL);
            assert(conshdlrdata->hashtable != NULL);
            assert(SCIPgetResultantAnd(scip, consanddatas[c]->origcons) != NULL);
            assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddatas[c]));
            assert(consanddatas[c] == (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)consanddatas[c])));
            assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons)));
            assert(consanddatas[c] == (CONSANDDATA*)(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons))));
         }
      }
   }

   /* free array of and-constraints */
   SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->andnegs), (*consdata)->sconsanddatas);
   SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->andcoefs), (*consdata)->sconsanddatas);
   SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->consanddatas), (*consdata)->sconsanddatas);

   SCIPfreeBlockMemory(scip, consdata);

   return SCIP_OKAY;
}

/** check the locks of an AND resultant and removes it from all global structures if the resultant is not locked anymore */
static
SCIP_RETCODE checkLocksAndRes(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_VAR*             res                 /**< resultant of AND constraint */
   )
{
   assert(scip != NULL);
   assert(res != NULL);

   /* the resultant has no locks left and might be dual fixed now, we need to delete all its cliques */
   if( SCIPvarIsActive(res) && SCIPvarGetNLocksDownType(res, SCIP_LOCKTYPE_MODEL) == 0
      && SCIPvarGetNLocksUpType(res, SCIP_LOCKTYPE_MODEL) == 0 && SCIPgetStage(scip) < SCIP_STAGE_FREETRANS )
   {
      SCIP_CALL( SCIPremoveVarFromGlobalStructures(scip, res) );
   }

   return SCIP_OKAY;
}

/** installs rounding locks for the given and-constraint associated with given coefficient */
static
SCIP_RETCODE lockRoundingAndCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   CONSANDDATA*const     consanddata,        /**< CONSANDDATA object for which we want to add the locks */
   SCIP_Real const       coef,               /**< coefficient which led to old locks */
   SCIP_Real const       lhs,                /**< left hand side */
   SCIP_Real const       rhs                 /**< right hand side */
   )
{
   SCIP_VAR** vars;
   int nvars;
   SCIP_VAR* res;
   SCIP_Bool haslhs;
   SCIP_Bool hasrhs;
   int v;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(!SCIPconsIsLockedType(cons, SCIP_LOCKTYPE_CONFLICT));
   assert(consanddata != NULL);
   assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
   assert(!SCIPisInfinity(scip, lhs));
   assert(!SCIPisInfinity(scip, -rhs));
   assert(SCIPisLE(scip, lhs, rhs));

   /* choose correct variable array to add locks for, we only add locks for now valid variables */
   if( consanddata->nnewvars > 0 )
   {
      vars = consanddata->newvars;
      nvars = consanddata->nnewvars;
   }
   else
   {
      vars = consanddata->vars;
      nvars = consanddata->nvars;
   }
   assert(vars != NULL || nvars == 0);

   res = SCIPgetResultantAnd(scip, consanddata->cons);
   assert(res != NULL);

   /* check which sites are infinity */
   haslhs = !SCIPisInfinity(scip, -lhs);
   hasrhs = !SCIPisInfinity(scip, rhs);

   if( SCIPconsIsLocked(cons) )
   {
      /* locking variables */
      if( SCIPisPositive(scip, coef) )
      {
         for( v = nvars - 1; v >= 0; --v )
         {
            SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, haslhs, hasrhs) );
         }
      }
      else
      {
         for( v = nvars - 1; v >= 0; --v )
         {
            SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, hasrhs, haslhs) );
         }
      }
      SCIP_CALL( SCIPlockVarCons(scip, res, cons, TRUE, TRUE) );
   }

   return SCIP_OKAY;
}

/** removes rounding locks for the given and-constraint associated with given coefficient */
static
SCIP_RETCODE unlockRoundingAndCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   CONSANDDATA*const     consanddata,        /**< CONSANDDATA object for which we want to delete the locks */
   SCIP_Real const       coef,               /**< coefficient which led to old locks */
   SCIP_Real const       lhs,                /**< left hand side which led to old locks */
   SCIP_Real const       rhs                 /**< right hand side which led to old locks */
   )
{
   SCIP_VAR** vars;
   int nvars;
   SCIP_VAR* res;
   SCIP_Bool haslhs;
   SCIP_Bool hasrhs;
   int v;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(!SCIPconsIsLockedType(cons, SCIP_LOCKTYPE_CONFLICT));
   assert(consanddata != NULL);
   assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
   assert(!SCIPisInfinity(scip, lhs));
   assert(!SCIPisInfinity(scip, -rhs));
   assert(SCIPisLE(scip, lhs, rhs));

   vars = consanddata->vars;
   nvars = consanddata->nvars;
   assert(vars != NULL || nvars == 0);

   if( consanddata->cons != NULL )
      res = SCIPgetResultantAnd(scip, consanddata->cons);
   else
      res = NULL;
   assert(res != NULL || nvars == 0);

   /* check which sites are infinity */
   haslhs = !SCIPisInfinity(scip, -lhs);
   hasrhs = !SCIPisInfinity(scip, rhs);

   if( SCIPconsIsLocked(cons) )
   {
      /* unlock variables */
      if( SCIPisPositive(scip, coef) )
      {
         for( v = nvars - 1; v >= 0; --v )
         {
            SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, haslhs, hasrhs) );
         }
      }
      else
      {
         for( v = nvars - 1; v >= 0; --v )
         {
            SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, hasrhs, haslhs) );
         }
      }

      if( res != NULL )
      {
         SCIP_CALL( SCIPunlockVarCons(scip, res, cons, TRUE, TRUE) );

         SCIP_CALL( checkLocksAndRes(scip, res) );
      }
   }

   return SCIP_OKAY;
}

/** prints pseudoboolean constraint in CIP format to file stream */
static
SCIP_RETCODE consdataPrint(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   FILE*const            file                /**< output file (or NULL for standard output) */
   )
{
   SCIP_CONSHDLR* conshdlr;
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONSDATA* consdata;
   SCIP_VAR*** monomialvars;
   SCIP_VAR** vars;
   SCIP_Real* coefs;
   SCIP_Real* monomialcoefs;
   SCIP_Real lhs;
   SCIP_Real rhs;
   int* monomialnvars;
   int nvars;
   int nmonomials;
   int v;

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

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   assert(consdata->lincons != NULL);

   /* gets number of variables in linear constraint */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );

   /* every variable in the linear constraint is either a linear variable or a term variable
    * but there can be additional fixed or negation-paired and-resultants with relevant and-constraints
    * whose values are already resolved in the linear constraint
    */
   assert(consdata->nlinvars + consdata->nconsanddatas >= nvars);

   /* initialize buffers for storing the terms and coefficients */
   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, nvars) );

   /* get sides of linear constraint */
   SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &lhs, &rhs) );
   assert(!SCIPisInfinity(scip, lhs));
   assert(!SCIPisInfinity(scip, -rhs));
   assert(SCIPisLE(scip, lhs, rhs));

   /* get variables and coefficient of linear constraint */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
   assert(coefs != NULL || nvars == 0);

   /* get and-data hashmap */
   conshdlr = SCIPconsGetHdlr(cons);
   assert(conshdlr != NULL);
   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);
   assert(conshdlrdata->hashmap != NULL);
   nmonomials = 0;

   /* collect all terms */
   for( v = 0; v < nvars; ++v )
   {
      CONSANDDATA* consanddata = NULL;
      SCIP_VAR** andvars = NULL;
      SCIP_VAR* var = vars[v];
      int nandvars = 0;

      assert(SCIPvarIsBinary(var));

      /* find and-constraint to standard or negated and-resultant */
      do
      {
         /* @todo: drop indicator variable */
         assert(!consdata->issoftcons || var != consdata->indvar);
         consanddata = (CONSANDDATA*)SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)var);

         if( consanddata != NULL )
         {
            SCIP_CONS* andcons = SCIPconsIsOriginal(cons) ? consanddata->origcons : consanddata->cons;

            andvars = SCIPgetVarsAnd(scip, andcons);
            nandvars = SCIPgetNVarsAnd(scip, andcons);

            break;
         }

         var = var == vars[v] ? SCIPvarGetNegatedVar(var) : vars[v];
      }
      while( var != vars[v] );

      if( consanddata == NULL )
      {
         assert(var != NULL);
         assert(var == vars[v]);
         monomialvars[nmonomials] = vars + v;
         monomialnvars[nmonomials] = 1;
      }
      else
      {
         SCIP_Bool fixed = nandvars == 0;
         SCIP_Bool negated = var != vars[v];

         if( fixed != negated )
         {
            if( !SCIPisInfinity(scip, -lhs) )
               lhs -= coefs[v];

            if( !SCIPisInfinity(scip, rhs) )
               rhs -= coefs[v];
         }

         if( fixed )
            continue;

         if( negated )
            coefs[v] *= -1.0;

         assert(andvars != NULL);
         monomialvars[nmonomials] = andvars;
         assert(nandvars >= 1);
         monomialnvars[nmonomials] = nandvars;
      }

      assert(!SCIPisZero(scip, coefs[v]));
      monomialcoefs[nmonomials] = coefs[v];
      ++nmonomials;
   }

   /* print left side */
   if( !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) && lhs != rhs ) /*lint !e777*/
      SCIPinfoMessage(scip, file, "%.15g <= ", lhs);

   /* print pseudoboolean polynomial */
   SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, NULL, monomialcoefs, monomialnvars, nmonomials, TRUE) );

   /* print right side */
   if( lhs == rhs ) /*lint !e777*/
      SCIPinfoMessage(scip, file, " == %.15g", rhs);
   else if( !SCIPisInfinity(scip, rhs) )
      SCIPinfoMessage(scip, file, " <= %.15g", rhs);
   else if( !SCIPisInfinity(scip, -lhs) )
      SCIPinfoMessage(scip, file, " >= %.15g", lhs);
   else
      SCIPinfoMessage(scip, file, " [free]");

   /* free buffers for storing the terms and coefficients */
   SCIPfreeBufferArray(scip, &monomialnvars);
   SCIPfreeBufferArray(scip, &monomialcoefs);
   SCIPfreeBufferArray(scip, &monomialvars);
   SCIPfreeBufferArray(scip, &coefs);
   SCIPfreeBufferArray(scip, &vars);

   /* print indicator variable if soft constraint */
   if( consdata->issoftcons )
   {
      SCIPinfoMessage(scip, file, " (indvar = ");
      SCIP_CALL( SCIPwriteVarName(scip, file, consdata->indvar, TRUE) );
      SCIPinfoMessage(scip, file, ")");
      assert(consdata->weight == SCIPvarGetObj(consdata->indvar)); /*lint !e777*/
   }

   return SCIP_OKAY;
}

/** creates and/or adds the resultant for a given term */
static
SCIP_RETCODE createAndAddAndCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLR*const   conshdlr,           /**< pseudoboolean constraint handler */
   SCIP_VAR**const       vars,               /**< array of variables to get and-constraints for */
   int const             nvars,              /**< number of variables to get and-constraints for */
   SCIP_Bool const       initial,            /**< should the LP relaxation of constraint be in the initial LP?
                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
   SCIP_Bool const       enforce,            /**< should the constraint be enforced during node processing?
                                              *   TRUE for model constraints, FALSE for additional, redundant
                                              *   constraints. */
   SCIP_Bool const       check,              /**< should the constraint be checked for feasibility?
                                              *   TRUE for model constraints, FALSE for additional, redundant
                                              *   constraints. */
   SCIP_Bool const       local,              /**< is constraint only valid locally?
                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching
                                              *   constraints. */
   SCIP_Bool const       modifiable,         /**< is constraint modifiable (subject to column generation)?
                                              *   Usually set to FALSE. In column generation applications, set to TRUE
                                              *   if pricing adds coefficients to this constraint. */
   SCIP_Bool const       dynamic,            /**< is constraint subject to aging?
                                              *   Usually set to FALSE. Set to TRUE for own cuts which
                                              *   are seperated as constraints. */
   SCIP_Bool const       stickingatnode,     /**< should the constraint always be kept at the node where it was added, even
                                              *   if it may be moved to a more global node?
                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent
                                              *   node data. */
   SCIP_CONS**const      andcons             /**< pointer to store and-constraint */
   )
{
   CONSANDDATA* newdata;
   CONSANDDATA* tmpdata;
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_Bool separate;
   SCIP_Bool propagate;
   SCIP_Bool removable;
   SCIP_Bool transformed;
   char name[SCIP_MAXSTRLEN];
   int v;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(vars != NULL);
   assert(nvars >= 1);
   assert(andcons != NULL);

   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);
   assert(conshdlrdata->hashtable != NULL);

   transformed = SCIPisTransformed(scip);

   /* allocate memory for a possible new consanddata object */
   SCIP_CALL( SCIPallocBlockMemory(scip, &newdata) );
   SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(newdata->vars), vars, nvars) );
   newdata->nvars = nvars;
   newdata->svars = nvars;
   newdata->newvars = NULL;
   newdata->nnewvars = 0;
   newdata->snewvars = 0;
   newdata->noriguses = 0;
   newdata->nuses = 0;
   newdata->istransformed = transformed;
   newdata->isoriginal = !transformed;
   newdata->cons = NULL;
   newdata->origcons = NULL;

   /* sort variables */
   SCIPsortPtr((void**)(newdata->vars), SCIPvarComp, nvars);

   /* get constraint from current hash table with same variables as cons0 */
   tmpdata = (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)newdata));

   /* if there is already the same and constraint created use this resultant */
   if( tmpdata != NULL )
   {
#ifndef NDEBUG
      SCIP_VAR* res;
#endif
      if( transformed )
      {
         assert(tmpdata->cons != NULL);
         *andcons = tmpdata->cons;

         assert(tmpdata->nuses > 0);
         /* increase usage of data object */
         ++(tmpdata->nuses);
      }
      else
      {
         assert(tmpdata->origcons != NULL);
         *andcons = tmpdata->origcons;

         assert(tmpdata->noriguses > 0);
         /* increase usage of data object */
         ++(tmpdata->noriguses);
      }
      assert(*andcons != NULL);

#ifndef NDEBUG
      res = SCIPgetResultantAnd(scip, *andcons);
      assert(res != NULL);

      /* check that we already have added this resultant to and-constraint entry */
      assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)res));
#endif
   }
   else
   {
      /* create new and-constraint */
      SCIP_CONS* newcons;
      SCIP_VAR* resultant;
      SCIP_IMPLINTTYPE impltype = SCIP_IMPLINTTYPE_STRONG;

      /* get resultant implied integral type */
      for( v = 0; v < nvars; ++v )
      {
         if( SCIPvarGetImplType(vars[v]) == SCIP_IMPLINTTYPE_WEAK )
         {
            impltype = SCIP_IMPLINTTYPE_WEAK;
            break;
         }
      }

      /* create auxiliary variable */
      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, ARTIFICIALVARNAMEPREFIX"%d", conshdlrdata->nallconsanddatas);
      SCIP_CALL( SCIPcreateVarImpl(scip, &resultant, name, 0.0, 1.0, 0.0,
            SCIP_VARTYPE_CONTINUOUS, impltype, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );

      /* add auxiliary variable to the problem */
      SCIP_CALL( SCIPaddVar(scip, resultant) );

      /* @todo: keep and-resultants defined to check debug solution */
#ifdef SCIP_DISABLED_CODE
#ifdef WITH_DEBUG_SOLUTION
      if( SCIPdebugIsMainscip(scip) )
      {
         SCIP_Real val = 1.0;
         SCIP_Real debugsolval;

         assert(nvars >= 1);
         for( v = nvars - 1; v >= 0; --v )
         {
            SCIP_CALL( SCIPdebugGetSolVal(scip, vars[v], &val) );
            assert(SCIPisFeasZero(scip, val) || SCIPisFeasEQ(scip, val, 1.0));

            if( val < 0.5 )
               break;
         }
         val = ((val < 0.5) ? 0.0 : 1.0);

         SCIP_CALL( SCIPdebugGetSolVal(scip, resultant, &debugsolval) );
         if( (SCIPvarIsOriginal(resultant) || SCIPvarIsTransformedOrigvar(resultant)) && !SCIPisFeasEQ(scip, debugsolval, val) )
         {
            SCIPerrorMessage("computed solution value %g for resultant <%s> violates debug solution value %g\n", val, SCIPvarGetName(resultant), debugsolval);
            SCIPABORT();
            return SCIP_ERROR; /*lint !e527*/
         }
         else if( !SCIPvarIsOriginal(resultant) && !SCIPvarIsTransformedOrigvar(resultant) )
         {
            SCIP_CALL( SCIPdebugAddSolVal(scip, resultant, val) );
         }
      }
#endif
#endif

      SCIP_CALL( SCIPgetBoolParam(scip, "constraints/" CONSHDLR_NAME "/nlcseparate", &separate) );
      SCIP_CALL( SCIPgetBoolParam(scip, "constraints/" CONSHDLR_NAME "/nlcpropagate", &propagate) );
      SCIP_CALL( SCIPgetBoolParam(scip, "constraints/" CONSHDLR_NAME "/nlcremovable", &removable) );

      /* we do not want to check the and constraints, so the check flag will be FALSE */

      /* create and add "and" constraint for the multiplication of the binary variables */
      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "andcons_%d", conshdlrdata->nallconsanddatas);
      SCIP_CALL( SCIPcreateConsAnd(scip, &newcons, name, resultant, newdata->nvars, newdata->vars,
            initial, separate, enforce, check && FALSE, propagate,
            local, modifiable, dynamic, removable, stickingatnode) ); /*lint !e506*/
      SCIP_CALL( SCIPaddCons(scip, newcons) );
      SCIPdebugPrintCons(scip, newcons, NULL);

      *andcons = newcons;
      assert(*andcons != NULL);

      /* resize data for all and-constraints if necessary */
      if( conshdlrdata->nallconsanddatas == conshdlrdata->sallconsanddatas )
      {
         SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(conshdlrdata->allconsanddatas), &(conshdlrdata->sallconsanddatas), SCIPcalcMemGrowSize(scip, conshdlrdata->sallconsanddatas + 1)) );
      }

      /* add new data object to global hash table */
      conshdlrdata->allconsanddatas[conshdlrdata->nallconsanddatas] = newdata;
      ++(conshdlrdata->nallconsanddatas);

      if( transformed )
      {
         newdata->cons = newcons;
         SCIP_CALL( SCIPcaptureCons(scip, newdata->cons) );

         /* lock upgrade to keep control */
         SCIPconsAddUpgradeLocks(newcons, +1);

         /* initialize usage of data object */
         newdata->nuses = 1;

         /* capture all variables */
         for( v = newdata->nvars - 1; v >= 0; --v )
         {
            SCIP_CALL( SCIPcaptureVar(scip, newdata->vars[v]) ); /*lint !e613*/
         }
      }
      else
      {
         newdata->origcons = newcons;
         SCIP_CALL( SCIPcaptureCons(scip, newdata->origcons) );

         /* initialize usage of data object */
         newdata->noriguses = 1;
      }

      /* no such and-constraint in current hash table: insert the new object into hash table */
      SCIP_CALL( SCIPhashtableInsert(conshdlrdata->hashtable, (void*)newdata) );

      /* insert new mapping */
      assert(!SCIPhashmapExists(conshdlrdata->hashmap, (void*)resultant));
      SCIP_CALL( SCIPhashmapInsert(conshdlrdata->hashmap, (void*)resultant, (void*)newdata) );

      /* release and-resultant and -constraint */
      SCIP_CALL( SCIPreleaseVar(scip, &resultant) );
      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );

      return SCIP_OKAY;
   }

   /* free memory */
   SCIPfreeBlockMemoryArray(scip, &(newdata->vars), newdata->svars);
   SCIPfreeBlockMemory(scip, &newdata);

   return SCIP_OKAY;
}

/** adds a term to the given pseudoboolean constraint */
static
SCIP_RETCODE addCoefTerm(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_VAR**const       vars,               /**< variables of the nonlinear term */
   int const             nvars,              /**< number of variables of the nonlinear term */
   SCIP_Real const       val                 /**< coefficient of constraint entry */
   )
{
   SCIP_CONSHDLR* conshdlr;
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONS* andcons;
   SCIP_CONSDATA* consdata;
   SCIP_VAR* res;

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

   if( SCIPisZero(scip, val) )
      return SCIP_OKAY;

   assert(vars != NULL);
   assert(nvars >= 1);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   conshdlr = SCIPconsGetHdlr(cons);
   assert(conshdlr != NULL);

   conshdlrdata =  SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   /* create (and add) and-constraint */
   SCIP_CALL( createAndAddAndCons(scip, conshdlr, vars, nvars,
         SCIPconsIsInitial(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsLocal(cons),
         SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsStickingAtNode(cons),
         &andcons) );
   assert(andcons != NULL);

   /* ensure memory size */
   if( consdata->nconsanddatas == consdata->sconsanddatas )
   {
      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(consdata->consanddatas), &(consdata->sconsanddatas), consdata->sconsanddatas + 1) );
   }

   res = SCIPgetResultantAnd(scip, andcons);
   assert(res != NULL);
   assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res) != NULL);

   consdata->consanddatas[consdata->nconsanddatas] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res);
   ++(consdata->nconsanddatas);

   /* add auxiliary variables to linear constraint */
   switch( consdata->linconstype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, res, val) );
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
      if( !SCIPisEQ(scip, val, 1.0) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefLogicor(scip, consdata->lincons, res) );
      break;
   case SCIP_LINEARCONSTYPE_KNAPSACK:
      if( !SCIPisIntegral(scip, val) || !SCIPisPositive(scip, val) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefKnapsack(scip, consdata->lincons, res, (SCIP_Longint) val) );
      break;
   case SCIP_LINEARCONSTYPE_SETPPC:
      if( !SCIPisEQ(scip, val, 1.0) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefSetppc(scip, consdata->lincons, res) );
      break;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
      if( !SCIPisIntegral(scip, val) || !SCIPisPositive(scip, val) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefEQKnapsack(scip, consdata->lincons, res, (SCIP_Longint) val) );
      break;
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   /* install rounding locks for all new variable */
   SCIP_CALL( lockRoundingAndCons(scip, cons, consdata->consanddatas[consdata->nconsanddatas - 1], val, consdata->lhs, consdata->rhs) );

   /* change flags */
   consdata->changed = TRUE;
   consdata->propagated = FALSE;
   consdata->presolved = FALSE;
   consdata->cliquesadded = FALSE;
   consdata->upgradetried = FALSE;

   return SCIP_OKAY;
}

/** changes left hand side of linear constraint */
static
SCIP_RETCODE chgLhsLinearCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< linear constraint */
   SCIP_LINEARCONSTYPE const constype,       /**< linear constraint type */
   SCIP_Real const       lhs                 /**< new left hand side of linear constraint */
   )
{
   switch( constype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      SCIP_CALL( SCIPchgLhsLinear(scip, cons, lhs) );
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
   case SCIP_LINEARCONSTYPE_KNAPSACK:
   case SCIP_LINEARCONSTYPE_SETPPC:
      SCIPerrorMessage("changing left hand side only allowed on standard lienar constraint \n");
      return SCIP_INVALIDDATA;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   return SCIP_OKAY;
}

/** changes right hand side of linear constraint */
static
SCIP_RETCODE chgRhsLinearCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< linear constraint */
   SCIP_LINEARCONSTYPE const constype,       /**< linear constraint type */
   SCIP_Real const       rhs                 /**< new right hand side of linear constraint */
   )
{
   switch( constype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      SCIP_CALL( SCIPchgRhsLinear(scip, cons, rhs) );
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
   case SCIP_LINEARCONSTYPE_KNAPSACK:
   case SCIP_LINEARCONSTYPE_SETPPC:
      SCIPerrorMessage("changing left hand side only allowed on standard lienar constraint \n");
      return SCIP_INVALIDDATA;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   return SCIP_OKAY;
}

/** sets left hand side of linear constraint */
static
SCIP_RETCODE chgLhs(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< linear constraint */
   SCIP_Real             lhs                 /**< new left hand side */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_VAR** vars;
   SCIP_Real* coefs;
   int nvars;
   SCIP_VAR** linvars;
   SCIP_Real* lincoefs;
   int nlinvars;
   SCIP_VAR** andress;
   SCIP_Real* andcoefs;
   SCIP_Bool* andnegs;
   int nandress;
   SCIP_Real oldlhs;
   SCIP_Real oldrhs;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(!SCIPconsIsLockedType(cons, SCIP_LOCKTYPE_CONFLICT));
   assert(!SCIPisInfinity(scip, lhs));

   /* adjust value to not be smaller than -inf */
   if ( SCIPisInfinity(scip, -lhs) )
      lhs = -SCIPinfinity(scip);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   /* get sides of linear constraint */
   SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &oldlhs, &oldrhs) );
   assert(!SCIPisInfinity(scip, oldlhs));
   assert(!SCIPisInfinity(scip, -oldrhs));
   assert(SCIPisLE(scip, oldlhs, oldrhs));

   /* check whether the side is not changed */
   if( SCIPisEQ(scip, oldlhs, lhs) )
      return SCIP_OKAY;

   /* gets number of variables in linear constraint */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andress, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andcoefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andnegs, nvars) );

   /* get variables and coefficient of linear constraint */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
   assert(coefs != NULL || nvars == 0);

   /* calculate all not artificial linear variables and all artificial and-resultants */
   SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars, andress, andcoefs, andnegs, &nandress) );
   assert(consdata->nconsanddatas == nandress);

   /* if necessary, update the rounding locks of variables */
   if( SCIPconsIsLocked(cons) )
   {
      SCIP_VAR** andvars;
      int nandvars;
      SCIP_Real val;
      int v;
      int c;

      assert(SCIPconsIsTransformed(cons));

      if( SCIPisInfinity(scip, -oldlhs) && !SCIPisInfinity(scip, -lhs) )
      {
         /* non-linear part */
         for( c = consdata->nconsanddatas - 1; c >= 0; --c )
         {
            CONSANDDATA* consanddata;
            SCIP_CONS* andcons;

            consanddata = consdata->consanddatas[c];
            assert(consanddata != NULL);

            andcons = consanddata->cons;
            assert(andcons != NULL);

            andvars = SCIPgetVarsAnd(scip, andcons);
            nandvars = SCIPgetNVarsAnd(scip, andcons);
            val = andnegs[c] ? -andcoefs[c] : andcoefs[c];

            /* lock variables */
            if( SCIPisPositive(scip, val) )
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
               }
            }
            else
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
               }
            }
         }
      }
      else if( !SCIPisInfinity(scip, -oldlhs) && SCIPisInfinity(scip, -lhs) )
      {
         /* non-linear part */
         for( c = consdata->nconsanddatas - 1; c >= 0; --c )
         {
            CONSANDDATA* consanddata;
            SCIP_CONS* andcons;

            consanddata = consdata->consanddatas[c];
            assert(consanddata != NULL);

            andcons = consanddata->cons;
            assert(andcons != NULL);

            andvars = SCIPgetVarsAnd(scip, andcons);
            nandvars = SCIPgetNVarsAnd(scip, andcons);
            val = andnegs[c] ? -andcoefs[c] : andcoefs[c];

            /* lock variables */
            if( SCIPisPositive(scip, val) )
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
               }
            }
            else
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
               }
            }
         }
      }
   }

   /* check whether the left hand side is increased, if and only if that's the case we maybe can propagate, tighten and add more cliques */
   if( SCIPisLT(scip, oldlhs, lhs) )
   {
      consdata->propagated = FALSE;
   }

   /* set new left hand side and update constraint data */
   SCIP_CALL( chgLhsLinearCons(scip, consdata->lincons, consdata->linconstype, lhs) );
   consdata->lhs = lhs;
   consdata->presolved = FALSE;
   consdata->changed = TRUE;

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &andnegs);
   SCIPfreeBufferArray(scip, &andcoefs);
   SCIPfreeBufferArray(scip, &andress);
   SCIPfreeBufferArray(scip, &lincoefs);
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &coefs);
   SCIPfreeBufferArray(scip, &vars);

   return SCIP_OKAY;
}

/** sets right hand side of pseudoboolean constraint */
static
SCIP_RETCODE chgRhs(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< linear constraint */
   SCIP_Real             rhs                 /**< new right hand side */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_VAR** vars;
   SCIP_Real* coefs;
   int nvars;
   SCIP_VAR** linvars;
   SCIP_Real* lincoefs;
   int nlinvars;
   SCIP_VAR** andress;
   SCIP_Real* andcoefs;
   SCIP_Bool* andnegs;
   int nandress;
   SCIP_Real oldlhs;
   SCIP_Real oldrhs;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(!SCIPconsIsLockedType(cons, SCIP_LOCKTYPE_CONFLICT));
   assert(!SCIPisInfinity(scip, -rhs));

   /* adjust value to not be larger than inf */
   if( SCIPisInfinity(scip, rhs) )
      rhs = SCIPinfinity(scip);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   /* get sides of linear constraint */
   SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &oldlhs, &oldrhs) );
   assert(!SCIPisInfinity(scip, oldlhs));
   assert(!SCIPisInfinity(scip, -oldrhs));
   assert(SCIPisLE(scip, oldlhs, oldrhs));

   /* check whether the side is not changed */
   if( SCIPisEQ(scip, oldrhs, rhs) )
      return SCIP_OKAY;

   /* gets number of variables in linear constraint */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andress, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andcoefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andnegs, nvars) );

   /* get variables and coefficient of linear constraint */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
   assert(coefs != NULL || nvars == 0);

   /* calculate all not artificial linear variables and all artificial and-resultants */
   SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars, andress, andcoefs, andnegs, &nandress) );
   assert(consdata->nconsanddatas == nandress);

   /* if necessary, update the rounding locks of variables */
   if( SCIPconsIsLocked(cons) )
   {
      SCIP_VAR** andvars;
      int nandvars;
      SCIP_Real val;
      int v;
      int c;

      assert(SCIPconsIsTransformed(cons));

      if( SCIPisInfinity(scip, oldrhs) && !SCIPisInfinity(scip, rhs) )
      {
         /* non-linear part */
         for( c = consdata->nconsanddatas - 1; c >= 0; --c )
         {
            CONSANDDATA* consanddata;
            SCIP_CONS* andcons;

            consanddata = consdata->consanddatas[c];
            assert(consanddata != NULL);

            andcons = consanddata->cons;
            assert(andcons != NULL);

            andvars = SCIPgetVarsAnd(scip, andcons);
            nandvars = SCIPgetNVarsAnd(scip, andcons);
            val = andnegs[c] ? -andcoefs[c] : andcoefs[c];

            /* lock variables */
            if( SCIPisPositive(scip, val) )
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
               }
            }
            else
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
               }
            }
         }
      }
      else if( !SCIPisInfinity(scip, oldrhs) && SCIPisInfinity(scip, rhs) )
      {
         /* non-linear part */
         for( c = consdata->nconsanddatas - 1; c >= 0; --c )
         {
            CONSANDDATA* consanddata;
            SCIP_CONS* andcons;

            consanddata = consdata->consanddatas[c];
            assert(consanddata != NULL);

            andcons = consanddata->cons;
            assert(andcons != NULL);

            andvars = SCIPgetVarsAnd(scip, andcons);
            nandvars = SCIPgetNVarsAnd(scip, andcons);
            val = andnegs[c] ? -andcoefs[c] : andcoefs[c];

            /* lock variables */
            if( SCIPisPositive(scip, val) )
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
               }
            }
            else
            {
               for( v = nandvars - 1; v >= 0; --v )
               {
                  SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
               }
            }
         }
      }
   }

   /* check whether the right hand side is decreased, if and only if that's the case we maybe can propagate, tighten and add more cliques */
   if( SCIPisGT(scip, oldrhs, rhs) )
   {
      consdata->propagated = FALSE;
   }

   /* set new right hand side and update constraint data */
   SCIP_CALL( chgRhsLinearCons(scip, consdata->lincons, consdata->linconstype, rhs) );
   consdata->rhs = rhs;
   consdata->presolved = FALSE;
   consdata->changed = TRUE;

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &andnegs);
   SCIPfreeBufferArray(scip, &andcoefs);
   SCIPfreeBufferArray(scip, &andress);
   SCIPfreeBufferArray(scip, &lincoefs);
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &coefs);
   SCIPfreeBufferArray(scip, &vars);

   return SCIP_OKAY;
}

/** create and-constraints and get all and-resultants */
static
SCIP_RETCODE createAndAddAnds(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLR*const   conshdlr,           /**< pseudoboolean constraint handler */
   SCIP_VAR**const*const terms,              /**< array of term variables to get and-constraints for */
   SCIP_Real*const       termcoefs,          /**< array of coefficients for and-constraints */
   int const             nterms,             /**< number of terms to get and-constraints for */
   int const*const       ntermvars,          /**< array of number of variable in each term */
   SCIP_Bool const       initial,            /**< should the LP relaxation of constraint be in the initial LP?
                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
   SCIP_Bool const       enforce,            /**< should the constraint be enforced during node processing?
                                              *   TRUE for model constraints, FALSE for additional, redundant
                                              *   constraints. */
   SCIP_Bool const       check,              /**< should the constraint be checked for feasibility?
                                              *   TRUE for model constraints, FALSE for additional, redundant
                                              *   constraints. */
   SCIP_Bool const       local,              /**< is constraint only valid locally?
                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching
                                              *   constraints. */
   SCIP_Bool const       modifiable,         /**< is constraint modifiable (subject to column generation)?
                                              *   Usually set to FALSE. In column generation applications, set to TRUE
                                              *   if pricing adds coefficients to this constraint. */
   SCIP_Bool const       dynamic,            /**< is constraint subject to aging?
                                              *   Usually set to FALSE. Set to TRUE for own cuts which
                                              *   are seperated as constraints. */
   SCIP_Bool const       stickingatnode,     /**< should the constraint always be kept at the node where it was added, even
                                              *   if it may be moved to a more global node?
                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent
                                              *   node data. */
   SCIP_CONS**const      andconss,           /**< array to store all created and-constraints for given terms */
   SCIP_Real*const       andvals,            /**< array to store all coefficients of and-constraints */
   SCIP_Bool*const       andnegs,            /**< array to store negation status of and-constraints */
   int*const             nandconss           /**< number of created and constraints */
   )
{
   int t;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(terms != NULL || nterms == 0);
   assert(ntermvars != NULL || nterms == 0);
   assert(andconss != NULL);
   assert(andvals != NULL);
   assert(nandconss != NULL);

   (*nandconss) = 0;

   /* loop over all terms and create/get all and constraints */
   for( t = 0; t < nterms; ++t )
   {
      if( !SCIPisZero(scip, termcoefs[t]) )
      {
         SCIP_CALL( createAndAddAndCons(scip, conshdlr, terms[t], ntermvars[t],
               initial, enforce, check, local, modifiable, dynamic, stickingatnode,
               &(andconss[*nandconss])) );
         assert(andconss[*nandconss] != NULL);
         andvals[*nandconss] = termcoefs[t];
         andnegs[*nandconss] = FALSE;
         ++(*nandconss);
      }
   }

   return SCIP_OKAY;
}

/** created linear constraint of pseudo boolean constraint */
static
SCIP_RETCODE createAndAddLinearCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLR*const   conshdlr,           /**< pseudoboolean constraint handler */
   SCIP_VAR**const       linvars,            /**< linear variables */
   int const             nlinvars,           /**< number of linear variables */
   SCIP_Real*const       linvals,            /**< linear coefficients */
   SCIP_VAR**const       andress,            /**< and-resultant variables */
   int const             nandress,           /**< number of and-resultant variables */
   SCIP_Real const*const andvals,            /**< and-resultant coefficients */
   SCIP_Bool*const       andnegs,            /**< and-resultant negation status */
   SCIP_Real*const       lhs,                /**< pointer to left hand side of linear constraint */
   SCIP_Real*const       rhs,                /**< pointer to right hand side of linear constraint */
   SCIP_Bool const       issoftcons,         /**< is this a soft constraint */
   SCIP_Bool const       initial,            /**< should the LP relaxation of constraint be in the initial LP?
                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
   SCIP_Bool const       separate,           /**< should the constraint be separated during LP processing?
                                              *   Usually set to TRUE. */
   SCIP_Bool const       enforce,            /**< should the constraint be enforced during node processing?
                                              *   TRUE for model constraints, FALSE for additional, redundant
                                              *   constraints. */
   SCIP_Bool const       check,              /**< should the constraint be checked for feasibility?
                                              *   TRUE for model constraints, FALSE for additional, redundant
                                              *   constraints. */
   SCIP_Bool const       propagate,          /**< should the constraint be propagated during node processing?
                                              *   Usually set to TRUE. */
   SCIP_Bool const       local,              /**< is constraint only valid locally?
                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching
                                              *   constraints. */
   SCIP_Bool const       modifiable,         /**< is constraint modifiable (subject to column generation)?
                                              *   Usually set to FALSE. In column generation applications, set to TRUE
                                              *   if pricing adds coefficients to this constraint. */
   SCIP_Bool const       dynamic,            /**< is constraint subject to aging?
                                              *   Usually set to FALSE. Set to TRUE for own cuts which
                                              *   are seperated as constraints. */
   SCIP_Bool const       removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user
                                              *   cuts'. */
   SCIP_Bool const       stickingatnode,     /**< should the constraint always be kept at the node where it was added, even
                                              *   if it may be moved to a more global node?
                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent
                                              *   node data. */
   SCIP_CONS**const      lincons,            /**< pointer to store created linear constraint */
   SCIP_LINEARCONSTYPE*const linconstype     /**< pointer to store the type of the linear constraint */
   )
{
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONSHDLR* upgrconshdlr;
   SCIP_CONS* cons;
   char name[SCIP_MAXSTRLEN];
   int v;
   SCIP_Bool created;
   SCIP_Bool integral;
   int nzero;
   int ncoeffspone;
   int ncoeffsnone;
   int ncoeffspint;
   int ncoeffsnint;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(linvars != NULL || nlinvars == 0);
   assert(linvals != NULL || nlinvars == 0);
   assert(andress != NULL || nandress == 0);
   assert(andvals != NULL || nandress == 0);
   assert(lhs != NULL);
   assert(rhs != NULL);
   assert(lincons != NULL);
   assert(linconstype != NULL);
   assert(nlinvars > 0 || nandress > 0);

   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   (*linconstype) = SCIP_LINEARCONSTYPE_INVALIDCONS;
   (*lincons) = NULL;
   cons = NULL;

   (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "pseudoboolean_linear%d", conshdlrdata->nlinconss);
   ++(conshdlrdata->nlinconss);

   created = FALSE;

   if( !modifiable )
   {
      SCIP_Real val;
      int nvars;

      /* calculate some statistics for upgrading on linear constraint */
      nzero = 0;
      ncoeffspone = 0;
      ncoeffsnone = 0;
      ncoeffspint = 0;
      ncoeffsnint = 0;
      integral = TRUE;
      nvars = nlinvars + nandress;

      /* calculate information over linear part */
      for( v = nlinvars - 1; v >= 0; --v )
      {
         val = linvals[v];

         if( SCIPisZero(scip, val) )
         {
            ++nzero;
            continue;
         }
         if( SCIPisEQ(scip, val, 1.0) )
            ++ncoeffspone;
         else if( SCIPisEQ(scip, val, -1.0) )
            ++ncoeffsnone;
         else if( SCIPisIntegral(scip, val) )
         {
            if( SCIPisPositive(scip, val) )
               ++ncoeffspint;
            else
               ++ncoeffsnint;
         }
         else
         {
            integral = FALSE;
            break;
         }
      }

      if( integral )
      {
         /* calculate information over and-resultants */
         for( v = nandress - 1; v >= 0; --v )
         {
            val = andvals[v];

            if( SCIPisZero(scip, val) )
            {
               ++nzero;
               continue;
            }
            if( SCIPisEQ(scip, val, 1.0) )
               ++ncoeffspone;
            else if( SCIPisEQ(scip, val, -1.0) )
               ++ncoeffsnone;
            else if( SCIPisIntegral(scip, val) )
            {
               if( SCIPisPositive(scip, val) )
                  ++ncoeffspint;
               else
                  ++ncoeffsnint;
            }
            else
            {
               integral = FALSE;
               break;
            }
         }
      }

      SCIPdebugMsg(scip, "While creating the linear constraint of the pseudoboolean constraint we found %d zero coefficients that were removed\n", nzero);

      /* try to upgrade to a special linear constraint */
      if( integral )
      {
         upgrconshdlr = SCIPfindConshdlr(scip, "logicor");

         /* check, if linear constraint can be upgraded to logic or constraint
          * - logic or constraints consist only of binary variables with a
          *   coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated):
          *        lhs     <= x1 + ... + xp - y1 - ... - yn <= rhs
          * - negating all variables y = (1-Y) with negative coefficients gives:
          *        lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n
          * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives:
          *        p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs
          * - logic or constraints have left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0
          *    -> without negations:  (lhs == 1 - n  and  rhs == +inf)  or  (lhs == -inf  and  rhs = p - 1)
          */
         if( upgrconshdlr != NULL && nvars > 2 && ncoeffspone + ncoeffsnone == nvars
            && ((SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, *rhs))
               || (SCIPisInfinity(scip, -*lhs) && SCIPisEQ(scip, *rhs, ncoeffspone - 1.0))) )
         {
            SCIP_VAR** transvars;
            int mult;

            SCIPdebugMsg(scip, "linear constraint will be logic-or constraint\n");

            /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
            mult = SCIPisInfinity(scip, *rhs) ? +1 : -1;

            /* get temporary memory */
            SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );

            /* negate positive or negative variables */
            for( v = 0; v < nlinvars; ++v )
            {
               if( mult * linvals[v] > 0.0 )
                  transvars[v] = linvars[v];
               else
               {
                  SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
               }
               assert(transvars[v] != NULL);
            }

            /* negate positive or negative variables */
            for( v = 0; v < nandress; ++v )
            {
               if( mult * andvals[v] > 0.0 )
                  transvars[nlinvars + v] = andress[v];
               else
               {
                  SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
                  andnegs[v] = TRUE;
               }
               assert(transvars[nlinvars + v] != NULL);
            }

            assert(!modifiable);
            /* create the constraint */
            SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, name, nvars, transvars,
                  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );

            created = TRUE;
            (*linconstype) = SCIP_LINEARCONSTYPE_LOGICOR;

            /* free temporary memory */
            SCIPfreeBufferArray(scip, &transvars);

            *lhs = 1.0;
            *rhs = SCIPinfinity(scip);
         }

         upgrconshdlr = SCIPfindConshdlr(scip, "setppc");

         /* check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint
          * - all set partitioning / packing / covering constraints consist only of binary variables with a
          *   coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated):
          *        lhs     <= x1 + ... + xp - y1 - ... - yn <= rhs
          * - negating all variables y = (1-Y) with negative coefficients gives:
          *        lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n
          * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives:
          *        p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs
          * - a set partitioning constraint has left hand side of +1.0, and right hand side of +1.0 : x(S) == 1.0
          *    -> without negations:  lhs == rhs == 1 - n  or  lhs == rhs == p - 1
          * - a set packing constraint has left hand side of -infinity, and right hand side of +1.0 : x(S) <= 1.0
          *    -> without negations:  (lhs == -inf  and  rhs == 1 - n)  or  (lhs == p - 1  and  rhs = +inf)
          * - a set covering constraint has left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0
          *    -> without negations:  (lhs == 1 - n  and  rhs == +inf)  or  (lhs == -inf  and  rhs = p - 1)
          */
         if( upgrconshdlr != NULL && !created && ncoeffspone + ncoeffsnone == nvars )
         {
            SCIP_VAR** transvars;
            int mult;

            if( SCIPisEQ(scip, *lhs, *rhs) && (SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) || SCIPisEQ(scip, *lhs, ncoeffspone - 1.0)) )
            {
               SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a set partitioning constraint\n");

               /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
               mult = SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) ? +1 : -1;

               /* get temporary memory */
               SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );

               /* negate positive or negative variables for linear variables */
               for( v = 0; v < nlinvars; ++v )
               {
                  if( mult * linvals[v] > 0.0 )
                     transvars[v] = linvars[v];
                  else
                  {
                     SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
                  }
                  assert(transvars[v] != NULL);
               }

               /* negate positive or negative variables for and-resultants */
               for( v = 0; v < nandress; ++v )
               {
                  if( mult * andvals[v] > 0.0 )
                     transvars[nlinvars + v] = andress[v];
                  else
                  {
                     SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
                     andnegs[v] = TRUE;
                  }
                  assert(transvars[nlinvars + v] != NULL);
               }

               /* create the constraint */
               assert(!modifiable);
               SCIP_CALL( SCIPcreateConsSetpart(scip, &cons, name, nvars, transvars,
                     initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );

               created = TRUE;
               (*linconstype) = SCIP_LINEARCONSTYPE_SETPPC;

               /* release temporary memory */
               SCIPfreeBufferArray(scip, &transvars);

               *lhs = 1.0;
               *rhs = 1.0;
            }
            else if( (SCIPisInfinity(scip, -*lhs) && SCIPisEQ(scip, *rhs, 1.0 - ncoeffsnone))
               || (SCIPisEQ(scip, *lhs, ncoeffspone - 1.0) && SCIPisInfinity(scip, *rhs)) )
            {
               SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a set packing constraint\n");

               /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
               mult = SCIPisInfinity(scip, -*lhs) ? +1 : -1;

               /* get temporary memory */
               SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );

               /* negate positive or negative variables for linear variables */
               for( v = 0; v < nlinvars; ++v )
               {
                  if( mult * linvals[v] > 0.0 )
                     transvars[v] = linvars[v];
                  else
                  {
                     SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
                  }
                  assert(transvars[v] != NULL);
               }

               /* negate positive or negative variables for and-resultants*/
               for( v = 0; v < nandress; ++v )
               {
                  if( mult * andvals[v] > 0.0 )
                     transvars[nlinvars + v] = andress[v];
                  else
                  {
                     SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
                     andnegs[v] = TRUE;
                  }
                  assert(transvars[nlinvars + v] != NULL);
               }

               /* create the constraint */
               assert(!modifiable);
               SCIP_CALL( SCIPcreateConsSetpack(scip, &cons, name, nvars, transvars,
                     initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );

               created = TRUE;
               (*linconstype) = SCIP_LINEARCONSTYPE_SETPPC;

               /* release temporary memory */
               SCIPfreeBufferArray(scip, &transvars);

               *lhs = -SCIPinfinity(scip);
               *rhs = 1.0;
            }
            else if( (SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, *rhs))
               || (SCIPisInfinity(scip, -*lhs) && SCIPisEQ(scip, *rhs, ncoeffspone - 1.0)) )
            {
               if( nvars != 1 )
               {
                  if( nvars == 2 )
                  {
                     SCIPwarningMessage(scip, "Does not expect this, because this constraint should be a set packing constraint.\n");
                  }
                  else
                  {
                     SCIPwarningMessage(scip, "Does not expect this, because this constraint should be a logicor constraint.\n");
                  }
               }
               SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a set covering constraint\n");

               /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
               mult = SCIPisInfinity(scip, *rhs) ? +1 : -1;

               /* get temporary memory */
               SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );

               /* negate positive or negative variables for linear variables */
               for( v = 0; v < nlinvars; ++v )
               {
                  if( mult * linvals[v] > 0.0 )
                     transvars[v] = linvars[v];
                  else
                  {
                     SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
                  }
                  assert(transvars[v] != NULL);
               }

               /* negate positive or negative variables for and-resultants*/
               for( v = 0; v < nandress; ++v )
               {
                  if( mult * andvals[v] > 0.0 )
                     transvars[nlinvars + v] = andress[v];
                  else
                  {
                     SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
                     andnegs[v] = TRUE;
                  }
                  assert(transvars[nlinvars + v] != NULL);
               }

               /* create the constraint */
               assert(!modifiable);
               SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, name, nvars, transvars,
                     initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );

               created = TRUE;
               (*linconstype) = SCIP_LINEARCONSTYPE_SETPPC;

               /* release temporary memory */
               SCIPfreeBufferArray(scip, &transvars);

               *lhs = 1.0;
               *rhs = SCIPinfinity(scip);
            }
         }

         upgrconshdlr = SCIPfindConshdlr(scip, "knapsack");

         /* check, if linear constraint can be upgraded to a knapsack constraint
          * - all variables must be binary
          * - all coefficients must be integral
          * - exactly one of the sides must be infinite
          */
         if( upgrconshdlr != NULL && !created && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars) && (SCIPisInfinity(scip, -*lhs) != SCIPisInfinity(scip, *rhs)) )
         {
            SCIP_VAR** transvars;
            SCIP_Longint* weights;
            SCIP_Longint capacity;
            SCIP_Longint weight;
            int mult;

            SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a knapsack constraint\n");

            /* get temporary memory */
            SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
            SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );

            /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
             * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
             */
            if( SCIPisInfinity(scip, *rhs) )
            {
               mult = -1;
               capacity = (SCIP_Longint)SCIPfeasFloor(scip, -*lhs);
            }
            else
            {
               mult = +1;
               capacity = (SCIP_Longint)SCIPfeasFloor(scip, *rhs);
            }

            /* negate positive or negative variables for linear variables */
            for( v = 0; v < nlinvars; ++v )
            {
               assert(SCIPisFeasIntegral(scip, linvals[v]));
               weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, linvals[v]);
               if( weight > 0 )
               {
                  transvars[v] = linvars[v];
                  weights[v] = weight;
               }
               else
               {
                  SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
                  weights[v] = -weight;
                  capacity -= weight;
               }
               assert(transvars[v] != NULL);
            }
            /* negate positive or negative variables for and-resultants */
            for( v = 0; v < nandress; ++v )
            {
               assert(SCIPisFeasIntegral(scip, andvals[v]));
               weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, andvals[v]);
               if( weight > 0 )
               {
                  transvars[nlinvars + v] = andress[v];
                  weights[nlinvars + v] = weight;
               }
               else
               {
                  SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
                  andnegs[v] = TRUE;
                  weights[nlinvars + v] = -weight;
                  capacity -= weight;
               }
               assert(transvars[nlinvars + v] != NULL);
            }

            /* create the constraint */
            SCIP_CALL( SCIPcreateConsKnapsack(scip, &cons, name, nvars, transvars, weights, capacity,
                  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );

            created = TRUE;
            (*linconstype) = SCIP_LINEARCONSTYPE_KNAPSACK;

            /* free temporary memory */
            SCIPfreeBufferArray(scip, &weights);
            SCIPfreeBufferArray(scip, &transvars);

            *lhs = -SCIPinfinity(scip);
            *rhs = capacity;
         }
#ifdef WITHEQKNAPSACK

         upgrconshdlr = SCIPfindConshdlr(scip, "eqknapsack");

         /* check, if linear constraint can be upgraded to a knapsack constraint
          * - all variables must be binary
          * - all coefficients must be integral
          * - both sides must be infinite
          */
         if( upgrconshdlr != NULL && !created && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars) && SCIPisEQ(scip, *lhs, *rhs) )
         {
            SCIP_VAR** transvars;
            SCIP_Longint* weights;
            SCIP_Longint capacity;
            SCIP_Longint weight;
            int mult;

            assert(!SCIPisInfinity(scip, *rhs));

            SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a equality-knapsack constraint\n");

            /* get temporary memory */
            SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
            SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );

            if( SCIPisPositive(scip, *rhs) )
            {
               mult = +1;
               capacity = (SCIP_Longint)SCIPfeasFloor(scip, *rhs);
            }
            else
            {
               mult = -1;
               capacity = (SCIP_Longint)SCIPfeasFloor(scip, -*rhs);
            }

            /* negate positive or negative variables for linear variables */
            for( v = 0; v < nlinvars; ++v )
            {
               assert(SCIPisFeasIntegral(scip, linvals[v]));
               weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, linvals[v]);
               if( weight > 0 )
               {
                  transvars[v] = linvars[v];
                  weights[v] = weight;
               }
               else
               {
                  SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
                  weights[v] = -weight;
                  capacity -= weight;
               }
               assert(transvars[v] != NULL);
            }
            /* negate positive or negative variables for and-resultants */
            for( v = 0; v < nandress; ++v )
            {
               assert(SCIPisFeasIntegral(scip, andvals[v]));
               weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, andvals[v]);
               if( weight > 0 )
               {
                  transvars[nlinvars + v] = andress[v];
                  weights[nlinvars + v] = weight;
               }
               else
               {
                  SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
                  andnegs[v] = TRUE;
                  weights[nlinvars + v] = -weight;
                  capacity -= weight;
               }
               assert(transvars[nlinvars + v] != NULL);
            }

            /* create the constraint */
            SCIP_CALL( SCIPcreateConsEqKnapsack(scip, &cons, name, nvars, transvars, weights, capacity,
                  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );

            created = TRUE;
            (*linconstype) = SCIP_LINEARCONSTYPE_EQKNAPSACK;

            /* free temporary memory */
            SCIPfreeBufferArray(scip, &weights);
            SCIPfreeBufferArray(scip, &transvars);

            *lhs = capacity;
            *rhs = capacity;
         }
#endif
      }
   }

   upgrconshdlr = SCIPfindConshdlr(scip, "linear");
   assert(created || upgrconshdlr != NULL);

   if( !created )
   {
      SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nlinvars, linvars, linvals, *lhs, *rhs,
            initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );

      (*linconstype) = SCIP_LINEARCONSTYPE_LINEAR;

      /* add all and-resultants */
      for( v = 0; v < nandress; ++v )
      {
         assert(andress[v] != NULL);

         /* add auxiliary variables to linear constraint */
         SCIP_CALL( SCIPaddCoefLinear(scip, cons, andress[v], andvals[v]) );
      }
   }

   assert(cons != NULL && *linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
   SCIPdebugPrintCons(scip, cons, NULL);
   *lincons = cons;

   /* @todo: add indicator variable */
   /* add hard constraint */
   if( !issoftcons )
   {
      SCIP_CALL( SCIPaddCons(scip, cons) );

      /* mark linear constraint not to be upgraded - otherwise we loose control over it */
      SCIPconsAddUpgradeLocks(cons, +1);
   }

   return SCIP_OKAY;
}

/** checks one original pseudoboolean constraint for feasibility of given solution */
static
SCIP_RETCODE checkOrigPbCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudo boolean constraint */
   SCIP_SOL*const        sol,                /**< solution to be checked, or NULL for current solution */
   SCIP_Bool*const       violated,           /**< pointer to store whether the constraint is violated */
   SCIP_Bool const       printreason         /**< should violation of constraint be printed */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_CONSHDLR* conshdlr;
   SCIP_CONSHDLRDATA* conshdlrdata;

   SCIP_VAR** vars;
   SCIP_Real* coefs;
   SCIP_Real lhs;
   SCIP_Real rhs;
   SCIP_Real activity;
   int nvars;
   int v;

   SCIP_Real lhsviol;
   SCIP_Real rhsviol;
   SCIP_Real absviol;
   SCIP_Real relviol;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(SCIPconsIsOriginal(cons));
   assert(violated != NULL);

   *violated = FALSE;

   SCIPdebugMsg(scip, "checking original pseudo boolean constraint <%s>\n", SCIPconsGetName(cons));
   SCIPdebugPrintCons(scip, cons, NULL);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   assert(consdata->lincons != NULL);
   assert(consdata->linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
   assert(SCIPconsIsOriginal(consdata->lincons));

   /* gets number of variables in linear constraint */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );

   /* get sides of linear constraint */
   SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &lhs, &rhs) );
   assert(!SCIPisInfinity(scip, lhs));
   assert(!SCIPisInfinity(scip, -rhs));
   assert(SCIPisLE(scip, lhs, rhs));

   /* get variables and coefficient of linear constraint */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
   assert(coefs != NULL || nvars == 0);

   /* every variable in the linear constraint is either a linear variable or a term variable
    * but there can be additional fixed or negation-paired and-resultants with relevant and-constraints
    * whose values are already resolved in the linear constraint
    */
   assert(consdata->nlinvars + consdata->nconsanddatas >= nvars);

   conshdlr = SCIPconsGetHdlr(cons);
   assert(conshdlr != NULL);

   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);
   assert(conshdlrdata->hashmap != NULL);

   activity = 0.0;

   /* compute pseudoboolean activity */
   for( v = 0; v < nvars; ++v )
   {
      CONSANDDATA* consanddata = NULL;
      SCIP_VAR* var = vars[v];
      SCIP_Real solval;

      /* find and-constraint to standard or negated and-resultant */
      do
      {
         consanddata = (CONSANDDATA*)SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)var);

         if( consanddata != NULL )
            break;

         var = var == vars[v] ? SCIPvarGetNegatedVar(var) : vars[v];
      }
      while( var != vars[v] );

      /* get linear solution */
      if( consanddata == NULL )
         solval = SCIPgetSolVal(scip, sol, vars[v]);
      /* get term solution */
      else
      {
         SCIP_CONS* andcons = consanddata->origcons;
         SCIP_VAR** andvars;
         int nandvars;
         int i;

         /* use transformed constraint if no original constraint exists */
         if( andcons == NULL )
            andcons = consanddata->cons;

         assert(SCIPgetResultantAnd(scip, andcons) == var);

         andvars = SCIPgetVarsAnd(scip, andcons);
         nandvars = SCIPgetNVarsAnd(scip, andcons);
         assert(andvars != NULL || nandvars == 0);

         solval = 1.0;

         for( i = 0; i < nandvars; ++i )
            solval *= SCIPgetSolVal(scip, sol, andvars[i]);

         if( var != vars[v] )
            solval = 1.0 - solval;
      }

      /* add activity contribution */
      activity += coefs[v] * solval;
   }

   SCIPdebugMsg(scip, "lhs = %g, activity = %g, rhs = %g\n", lhs, activity, rhs);

   /* calculate absolute and relative violation */
   lhsviol = lhs - activity;
   rhsviol = activity - rhs;

   if(lhsviol > rhsviol)
   {
      absviol = lhsviol;
      relviol = SCIPrelDiff(lhs, activity);
   }
   else
   {
      absviol = rhsviol;
      relviol = SCIPrelDiff(activity, rhs);
   }

   /* update absolute and relative violation of the solution */
   if( sol != NULL )
      SCIPupdateSolConsViolation(scip, sol, absviol, relviol);

   /* check left hand side for violation */
   if( SCIPisFeasLT(scip, activity, lhs) )
   {
      if( printreason )
      {
         SCIP_CALL( SCIPprintCons(scip, cons, NULL ) );
         SCIPinfoMessage(scip, NULL, ";\n");
         SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", lhs - activity);

         /* print linear constraint in SCIP_DEBUG mode too */
         SCIPdebugPrintCons(scip, SCIPconsGetData(cons)->lincons, NULL);
      }

      *violated = TRUE;
   }

   /* check right hand side for violation */
   if( SCIPisFeasGT(scip, activity, rhs) )
   {
      if( printreason )
      {
         SCIP_CALL( SCIPprintCons(scip, cons, NULL ) );
         SCIPinfoMessage(scip, NULL, ";\n");
         SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", activity - rhs);
      }

      *violated = TRUE;
   }

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &coefs);
   SCIPfreeBufferArray(scip, &vars);

   return SCIP_OKAY;
}

/** checks all and-constraints inside the pseudoboolean constraint handler for feasibility of given solution or current
 *  solution
 */
static
SCIP_RETCODE checkAndConss(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLR*const   conshdlr,           /**< pseudo boolean constraint handler */
   SCIP_SOL*const        sol,                /**< solution to be checked, or NULL for current solution */
   SCIP_Bool*const       violated            /**< pointer to store whether the constraint is violated */
   )
{
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONS* andcons;
   SCIP_VAR** vars;
   SCIP_VAR* res;
   int nvars;
   int c;
   int v;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(violated != NULL);

   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   *violated = FALSE;

   for( c = conshdlrdata->nallconsanddatas - 1; c >= 0; --c )
   {
      SCIP_Real solval;
      SCIP_Real minsolval;
      SCIP_Real sumsolval;
      SCIP_Real viol;

      if( !conshdlrdata->allconsanddatas[c]->istransformed )
         continue;

      andcons = conshdlrdata->allconsanddatas[c]->cons;

      /* need to check even locally deleted constraints */
      if( andcons == NULL ) /*|| !SCIPconsIsActive(andcons) )*/
         continue;

      vars = SCIPgetVarsAnd(scip, andcons);
      nvars = SCIPgetNVarsAnd(scip, andcons);
      assert(vars != NULL || nvars == 0);

      res = SCIPgetResultantAnd(scip, andcons);
      assert(res != NULL);

      /* check if the and-constraint is violated */
      minsolval = 1.0;
      sumsolval = 0.0;
      for( v = nvars - 1; v >= 0; --v )
      {
         solval = SCIPgetSolVal(scip, sol, vars[v]);

         if( solval < minsolval )
            minsolval = solval;

         sumsolval += solval;
      }

      /* the resultant must be at most as large as every operator
       * and at least as large as one minus the sum of negated operators
       */
      solval = SCIPgetSolVal(scip, sol, res);
      viol = MAX3(0.0, solval - minsolval, sumsolval - (nvars - 1.0 + solval));

      if( SCIPisFeasPositive(scip, viol) )
      {
         /* only reset constraint age if we are in enforcement */
         if( sol == NULL )
         {
            SCIP_CALL( SCIPresetConsAge(scip, andcons) );
         }

         *violated = TRUE;
         break;
      }
      else if( sol == NULL )
      {
         SCIP_CALL( SCIPincConsAge(scip, andcons) );
      }
   }

   return SCIP_OKAY;
}

/** creates by copying and captures a linear constraint */
static
SCIP_RETCODE copyConsPseudoboolean(
   SCIP*const            targetscip,         /**< target SCIP data structure */
   SCIP_CONS**           targetcons,         /**< pointer to store the created target constraint */
   SCIP*const            sourcescip,         /**< source SCIP data structure */
   SCIP_CONS*const       sourcecons,         /**< source constraint which will be copied */
   const char*           name,               /**< name of constraint */
   SCIP_HASHMAP*const    varmap,             /**< a SCIP_HASHMAP mapping variables of the source SCIP to corresponding
                                              *   variables of the target SCIP */
   SCIP_HASHMAP*const    consmap,            /**< a hashmap to store the mapping of source constraints to the corresponding
                                              *   target constraints */
   SCIP_Bool const       initial,            /**< should the LP relaxation of constraint be in the initial LP? */
   SCIP_Bool const       separate,           /**< should the constraint be separated during LP processing? */
   SCIP_Bool const       enforce,            /**< should the constraint be enforced during node processing? */
   SCIP_Bool const       check,              /**< should the constraint be checked for feasibility? */
   SCIP_Bool const       propagate,          /**< should the constraint be propagated during node processing? */
   SCIP_Bool const       local,              /**< is constraint only valid locally? */
   SCIP_Bool const       modifiable,         /**< is constraint modifiable (subject to column generation)? */
   SCIP_Bool const       dynamic,            /**< is constraint subject to aging? */
   SCIP_Bool const       removable,          /**< should the relaxation be removed from the LP due to aging or cleanup? */
   SCIP_Bool const       stickingatnode,     /**< should the constraint always be kept at the node where it was added, even
                                              *   if it may be moved to a more global node? */
   SCIP_Bool const       global,             /**< create a global or a local copy? */
   SCIP_Bool*const       valid               /**< pointer to store if the copying was valid */
   )
{
   SCIP_CONSDATA* sourceconsdata;
   SCIP_CONS* sourcelincons;

   assert(targetscip != NULL);
   assert(targetcons != NULL);
   assert(sourcescip != NULL);
   assert(sourcecons != NULL);
   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0);
   assert(valid != NULL);

   *valid = TRUE;

   sourceconsdata = SCIPconsGetData(sourcecons);
   assert(sourceconsdata != NULL);

   /* get linear constraint */
   sourcelincons = sourceconsdata->lincons;
   assert(sourcelincons != NULL);

   /* get copied version of linear constraint */
   if( !SCIPconsIsDeleted(sourcelincons) )
   {
      SCIP_CONSHDLR* conshdlrlinear;
      SCIP_CONS* targetlincons;
      SCIP_CONS** targetandconss;
      SCIP_Real* targetandcoefs;
      int ntargetandconss;
      SCIP_LINEARCONSTYPE targetlinconstype;

      targetlinconstype = sourceconsdata->linconstype;

      switch( targetlinconstype )
      {
      case SCIP_LINEARCONSTYPE_LINEAR:
         conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
         assert(conshdlrlinear != NULL);
         break;
      case SCIP_LINEARCONSTYPE_LOGICOR:
         conshdlrlinear = SCIPfindConshdlr(sourcescip, "logicor");
         assert(conshdlrlinear != NULL);
         break;
      case SCIP_LINEARCONSTYPE_KNAPSACK:
         conshdlrlinear = SCIPfindConshdlr(sourcescip, "knapsack");
         assert(conshdlrlinear != NULL);
         break;
      case SCIP_LINEARCONSTYPE_SETPPC:
         conshdlrlinear = SCIPfindConshdlr(sourcescip, "setppc");
         assert(conshdlrlinear != NULL);
         break;
#ifdef WITHEQKNAPSACK
      case SCIP_LINEARCONSTYPE_EQKNAPSACK:
         conshdlrlinear = SCIPfindConshdlr(sourcescip, "eqknapsack");
         assert(conshdlrlinear != NULL);
         break;
#endif
      case SCIP_LINEARCONSTYPE_INVALIDCONS:
      default:
         SCIPerrorMessage("unknown linear constraint type\n");
         return SCIP_INVALIDDATA;
      }

      if( conshdlrlinear == NULL ) /*lint !e774*/
      {
         SCIPerrorMessage("linear constraint handler not found\n");
         return SCIP_INVALIDDATA;
      }

      targetlincons = NULL;

      /* copy linear constraint */
      SCIP_CALL( SCIPgetConsCopy(sourcescip, targetscip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
            SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
            SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
            SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );

      if( *valid )
      {
         assert(targetlincons != NULL);
         assert(SCIPconsGetHdlr(targetlincons) != NULL);
         /* @note due to copying special linear constraints, now leads only to simple linear constraints, we check that
          *       our target constraint handler is the same as our source constraint handler of the linear constraint,
          *       if copying was not valid
          */
         if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(targetlincons)), "linear") == 0 )
            targetlinconstype = SCIP_LINEARCONSTYPE_LINEAR;
      }

      targetandconss = NULL;
      targetandcoefs = NULL;
      ntargetandconss = 0;

      if( *valid )
      {
         SCIP_CONSHDLR* conshdlrand;
         int c;
         int nsourceandconss;
         SCIP_HASHTABLE* linconsvarsmap;
         SCIP_VAR** targetlinvars;
         SCIP_Real* targetlincoefs;
         int ntargetlinvars;

         conshdlrand = SCIPfindConshdlr(sourcescip, "and");
         assert(conshdlrand != NULL);

         nsourceandconss = sourceconsdata->nconsanddatas;

         /* allocate temporary memory */
         SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetandconss, nsourceandconss) );
         SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetandcoefs, nsourceandconss) );

         /* get the number of vars in the copied linear constraint and allocate buffers
          * for the variables and the coefficients
          */
         SCIP_CALL( getLinearConsNVars(targetscip, targetlincons, targetlinconstype, &ntargetlinvars) );
         SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetlinvars, ntargetlinvars) );
         SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetlincoefs, ntargetlinvars) );

         /* retrieve the variables of the copied linear constraint */
         SCIP_CALL( getLinearConsVarsData(targetscip, targetlincons, targetlinconstype,
                                          targetlinvars, targetlincoefs, &ntargetlinvars) );

         /* now create a hashtable and insert the variables into it, so that it
          * can be checked in constant time if a variable was removed due to
          * compressed copying when looping over the and resultants
          */
         SCIP_CALL( SCIPhashtableCreate(&linconsvarsmap, SCIPblkmem(targetscip), ntargetlinvars, SCIPvarGetHashkey,
                                        SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );

         for( c = 0 ; c < ntargetlinvars; ++c )
         {
            SCIP_CALL( SCIPhashtableInsert(linconsvarsmap, targetlinvars[c]) );
         }

         /* free the buffer arrays that were only required for building the hastable */
         SCIPfreeBufferArray(sourcescip, &targetlincoefs);
         SCIPfreeBufferArray(sourcescip, &targetlinvars);

         for( c = 0 ; c < nsourceandconss; ++c )
         {
            CONSANDDATA* consanddata;
            SCIP_CONS* oldcons;
            SCIP_VAR* targetandresultant;
            SCIP_Bool validand;

            consanddata = sourceconsdata->consanddatas[c];
            assert(consanddata != NULL);
            oldcons = SCIPconsIsOriginal(sourcecons) ? consanddata->origcons : consanddata->cons;
            targetandresultant = (SCIP_VAR*) SCIPhashmapGetImage(varmap, SCIPgetResultantAnd(sourcescip, oldcons));

            /* if compressed copying is active, the resultant might have been fixed or not required by the linear
             * constraint so that we do not need to add it to the pseudo boolean constraint in these cases
             */
            if( targetandresultant == NULL || !SCIPhashtableExists(linconsvarsmap, targetandresultant) )
               continue;

            validand = TRUE;

            targetandconss[ntargetandconss] = NULL;

            /* copy and-constraints */
            SCIP_CALL( SCIPgetConsCopy(sourcescip, targetscip, oldcons, &targetandconss[ntargetandconss], conshdlrand, varmap, consmap, SCIPconsGetName(oldcons),
                  SCIPconsIsInitial(oldcons), SCIPconsIsSeparated(oldcons), SCIPconsIsEnforced(oldcons), SCIPconsIsChecked(oldcons),
                  SCIPconsIsPropagated(oldcons), SCIPconsIsLocal(oldcons), SCIPconsIsModifiable(oldcons), SCIPconsIsDynamic(oldcons),
                  SCIPconsIsRemovable(oldcons), SCIPconsIsStickingAtNode(oldcons), global, &validand) );

            *valid &= validand;

            if( validand )
            {
               targetandcoefs[ntargetandconss] = sourceconsdata->andcoefs[c];
               ++ntargetandconss;
            }
         }

         SCIPhashtableFree(&linconsvarsmap);
         assert(ntargetandconss <= ntargetlinvars);
      }

      if( *valid )  /* cppcheck-suppress duplicateCondition */
      {
         SCIP_Real targetrhs;
         SCIP_Real targetlhs;

         SCIP_VAR* indvar;
         const char* consname;

         /* third the indicator and artificial integer variable part */
         assert(sourceconsdata->issoftcons == (sourceconsdata->indvar != NULL));
         indvar = sourceconsdata->indvar;

         /* copy indicator variable */
         if( indvar != NULL )
         {
            assert(*valid);
            SCIP_CALL( SCIPgetVarCopy(sourcescip, targetscip, indvar, &indvar, varmap, consmap, global, valid) );
            assert(!(*valid) || indvar != NULL);
         }

         if( *valid )
         {
            if( name != NULL )
               consname = name;
            else
               consname = SCIPconsGetName(sourcecons);

            /* get new left and right hand sides of copied linear constraint since
             * they might have changed if compressed copying is used
             */
            SCIP_CALL( getLinearConsSides(targetscip, targetlincons, targetlinconstype, &targetlhs, &targetrhs) );

            /* create new pseudoboolean constraint */
            /* coverity[var_deref_op] */
            /* coverity[var_deref_model] */
            /* Note that due to compression the and constraints might have disappeared in which case ntargetandconss == 0. */
            SCIP_CALL( SCIPcreateConsPseudobooleanWithConss(targetscip, targetcons, consname, targetlincons,
                  targetlinconstype, targetandconss, targetandcoefs, ntargetandconss, indvar, sourceconsdata->weight,
                  sourceconsdata->issoftcons, targetlhs, targetrhs, initial, separate, enforce, check, propagate,
                  local, modifiable, dynamic, removable, stickingatnode) );
         }
      }

      if( !(*valid) && !SCIPisConsCompressionEnabled(sourcescip) )
      {
         SCIPverbMessage(sourcescip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy constraint <%s>\n", SCIPconsGetName(sourcecons));
      }

      /* release copied linear constraint */
      if( targetlincons != NULL )
      {
         SCIP_CALL( SCIPreleaseCons(targetscip, &targetlincons) );
      }

      /* release copied and constraint */
      if( targetandconss != NULL )
      {
         int c;

         assert(ntargetandconss <= sourceconsdata->nconsanddatas);

         for( c = 0 ; c < ntargetandconss; ++c )
         {
            if( targetandconss[c] != NULL )
            {
               SCIP_CALL( SCIPreleaseCons(targetscip, &targetandconss[c]) );
            }
         }
      }

      /* free temporary memory */
      SCIPfreeBufferArrayNull(sourcescip, &targetandcoefs);
      SCIPfreeBufferArrayNull(sourcescip, &targetandconss);
   }
   else
      *valid = FALSE;

   return SCIP_OKAY;
}

/** compute all changes in consanddatas array */
static
SCIP_RETCODE computeConsAndDataChanges(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLRDATA*const conshdlrdata      /**< pseudoboolean constraint handler data */
   )
{
   CONSANDDATA** allconsanddatas;
   CONSANDDATA* consanddata;
   int c;

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

   allconsanddatas = conshdlrdata->allconsanddatas;
   assert(allconsanddatas != NULL);
   assert(conshdlrdata->nallconsanddatas >= 0);
   assert(conshdlrdata->nallconsanddatas <= conshdlrdata->sallconsanddatas);

   for( c = conshdlrdata->nallconsanddatas - 1; c >= 0; --c )
   {
      SCIP_CONS* cons;
      SCIP_VAR** vars;
      int nvars;
      SCIP_VAR** newvars;
      int nnewvars;
      int v;

      consanddata = allconsanddatas[c];

      if( !consanddata->istransformed )
         continue;

      if( consanddata->nuses == 0 )
         continue;

      vars = consanddata->vars;
      nvars = consanddata->nvars;
      assert(vars != NULL || nvars == 0);
      assert(consanddata->nnewvars == 0 && ((consanddata->snewvars > 0) == (consanddata->newvars != NULL)));

      if( nvars == 0 )
      {
#ifndef NDEBUG
         /* if an old consanddata-object has no variables left there should be no new variables */
         if( consanddata->cons != NULL )
            assert(SCIPgetNVarsAnd(scip, consanddata->cons) == 0);
#endif
         continue;
      }

      cons = consanddata->cons;
      assert(cons != NULL);

      if( SCIPconsIsDeleted(cons) )
         continue;

      /* sort and-variables */
      if( !SCIPisAndConsSorted(scip, consanddata->cons) )
      {
         SCIP_CALL( SCIPsortAndCons(scip, consanddata->cons) );
         assert(SCIPisAndConsSorted(scip, consanddata->cons));
      }

      /* get new and-variables */
      nnewvars = SCIPgetNVarsAnd(scip, consanddata->cons);
      newvars = SCIPgetVarsAnd(scip, consanddata->cons);

      /* stop if the constraint has no variables or there was an error (coverity issue) */
      if( nnewvars <= 0 )
         continue;

#ifndef NDEBUG
      /* check that old variables are sorted */
      for( v = nvars - 1; v > 0; --v )
         assert(SCIPvarGetIndex(vars[v]) >= SCIPvarGetIndex(vars[v - 1]));
      /* check that new variables are sorted */
      for( v = nnewvars - 1; v > 0; --v )
         assert(SCIPvarGetIndex(newvars[v]) >= SCIPvarGetIndex(newvars[v - 1]));
#endif

      /* check for changings, if and-constraint did not change we do not need to copy all variables */
      if( nvars == nnewvars )
      {
         SCIP_Bool changed;

         changed = FALSE;

         /* check each variable */
         for( v = nvars - 1; v >= 0; --v )
         {
            if( vars[v] != newvars[v] )
            {
               changed = TRUE;
               break;
            }
         }

         if( !changed )
            continue;
      }

      /* resize newvars array if necessary */
      if( nnewvars > consanddata->snewvars )
      {
         SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(consanddata->newvars), &(consanddata->snewvars), nnewvars) );
      }

      /* copy all variables */
      BMScopyMemoryArray(consanddata->newvars, newvars, nnewvars);
      consanddata->nnewvars = nnewvars;

      /* capture all variables */
      for( v = consanddata->nnewvars - 1; v >= 0; --v )
      {
         /* in original problem the variables was already deleted */
         assert(consanddata->newvars[v] != NULL);
         SCIP_CALL( SCIPcaptureVar(scip, consanddata->newvars[v]) );
      }
   }

   return SCIP_OKAY;
}

/** remove old locks */
static
SCIP_RETCODE removeOldLocks(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   CONSANDDATA*const     consanddata,        /**< CONSANDDATA object for which we want to delete the locks and the
                                              *   capture of the corresponding and-constraint */
   SCIP_Real const       coef,               /**< coefficient which led to old locks */
   SCIP_Real const       lhs,                /**< left hand side which led to old locks */
   SCIP_Real const       rhs                 /**< right hand side which led to old locks */
   )
{
   assert(scip != NULL);
   assert(cons != NULL);
   assert(consanddata != NULL);
   assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
   assert(!SCIPisInfinity(scip, lhs));
   assert(!SCIPisInfinity(scip, -rhs));
   assert(SCIPisLE(scip, lhs, rhs));

   /* remove rounding locks */
   SCIP_CALL( unlockRoundingAndCons(scip, cons, consanddata, coef, lhs, rhs) );

   assert(consanddata->cons != NULL);

   return SCIP_OKAY;
}

/** add new locks */
static
SCIP_RETCODE addNewLocks(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   CONSANDDATA*const     consanddata,        /**< CONSANDDATA object for which we want to delete the locks and the
                                              *   capture of the corresponding and-constraint */
   SCIP_Real const       coef,               /**< coefficient which lead to new locks */
   SCIP_Real const       lhs,                /**< left hand side which lead to new locks */
   SCIP_Real const       rhs                 /**< right hand side which lead to new locks */
   )
{
   assert(scip != NULL);
   assert(cons != NULL);
   assert(consanddata != NULL);
   assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
   assert(!SCIPisInfinity(scip, lhs));
   assert(!SCIPisInfinity(scip, -rhs));
   assert(SCIPisLE(scip, lhs, rhs));

   /* add rounding locks due to old variables in consanddata object */
   SCIP_CALL( lockRoundingAndCons(scip, cons, consanddata, coef, lhs, rhs) );

   assert(consanddata->cons != NULL);

   return SCIP_OKAY;
}

/** update all locks inside this constraint and all captures on all and-constraints */
static
SCIP_RETCODE correctLocksAndCaptures(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   SCIP_Real const       newlhs,             /**< new left hand side of pseudoboolean constraint */
   SCIP_Real const       newrhs,             /**< new right hand side of pseudoboolean constraint */
   SCIP_VAR**const       andress,            /**< new and-resultants in pseudoboolean constraint */
   SCIP_Real*const       andcoefs,           /**< new and-resultants-coeffcients in pseudoboolean constraint */
   SCIP_Bool*const       andnegs,            /**< new negation status of and-resultants in pseudoboolean constraint */
   int const             nandress            /**< number of current and-resultants in pseudoboolean constraint */
   )
{
   CONSANDDATA** newconsanddatas;
   int nnewconsanddatas;
   int snewconsanddatas;
   SCIP_Real* newandcoefs;
   SCIP_Real* oldandcoefs;
   SCIP_Bool* newandnegs;
   SCIP_Bool* oldandnegs;
   CONSANDDATA** consanddatas;
   int nconsanddatas;
   SCIP_CONSDATA* consdata;
   int oldnvars;
   int c;
   int c1;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlrdata != NULL);
   assert(conshdlrdata->hashmap != NULL);
   assert(andress != NULL || nandress == 0);
   assert(andcoefs != NULL || nandress == 0);
   assert(!SCIPisInfinity(scip, newlhs));
   assert(!SCIPisInfinity(scip, -newrhs));
   assert(SCIPisLE(scip, newlhs, newrhs));

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   /* sort and-constraints by the problem indices of corresponding and-resultants */
   SCIPsortPtrRealBool((void**)(consdata->consanddatas), consdata->andcoefs, consdata->andnegs, resvarCompWithInactive, consdata->nconsanddatas);

   /* sort and-resultants by their problem indices */
   SCIPsortPtrRealBool((void**)andress, andcoefs, andnegs, resvarComp, nandress);

   consanddatas = consdata->consanddatas;
   oldandcoefs = consdata->andcoefs;
   oldandnegs = consdata->andnegs;
   nconsanddatas = consdata->nconsanddatas;
   assert(consanddatas != NULL || nconsanddatas == 0);
   assert(oldandcoefs != NULL || nconsanddatas == 0);

   snewconsanddatas = nconsanddatas + nandress;

   /* allocate new block memory arrays */
   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &newconsanddatas, snewconsanddatas) );
   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &newandcoefs, snewconsanddatas) );
   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &newandnegs, snewconsanddatas) );

   nnewconsanddatas = 0;

   /* collect new consanddata objects and update locks and captures */
   for( c = 0, c1 = 0; c < nconsanddatas && c1 < nandress; )
   {
      SCIP_CONS* andcons;
      SCIP_VAR* res1;
      SCIP_VAR* res2;
      int compval;

      assert(consanddatas[c] != NULL);

      /* consanddata object could have been deleted in the last presolving round */
      if( !consanddatas[c]->istransformed )
      {
         ++c;
         consdata->changed = TRUE;
         consdata->upgradetried = FALSE;
         continue;
      }

      andcons = consanddatas[c]->cons;
      assert(andcons != NULL);

      if( andcons == NULL ) /*lint !e774*/
      {
         ++c;
         consdata->changed = TRUE;
         consdata->upgradetried = FALSE;
         continue;
      }
      else if( SCIPconsIsDeleted(andcons) )
      {
         /* remove rounding locks, because the and constraint was deleted  */
         SCIP_CALL( unlockRoundingAndCons(scip, cons, consanddatas[c],
               oldandnegs[c] ? -oldandcoefs[c] : oldandcoefs[c], consdata->lhs, consdata->rhs) );
         ++c;
         consdata->changed = TRUE;
         consdata->upgradetried = FALSE;
         continue;
      }
      assert(andcons != NULL);

      /* get and-resultants of consanddata object in constraint data */
      res1 = SCIPgetResultantAnd(scip, andcons);
      assert(res1 != NULL);
      assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res1) == consanddatas[c]);

      /* get and-resultants in new corresponding linear constraint */
      res2 = andress[c1];
      assert(res2 != NULL);
      assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2) != NULL);

      /* get comparison value */
      compval = resvarComp((void*)res1, (void*)res2);

      /* collect new consanddata objects sorted with respect to the problem index of corresponding and-resultants */
      if( compval == -1 )
      {
         assert(!SCIPisZero(scip, oldandcoefs[c]));
         assert(consanddatas[c]->nuses > 0);
         --(consanddatas[c]->nuses);

         /* remove old locks */
         SCIP_CALL( removeOldLocks(scip, cons, consanddatas[c], oldandnegs[c] ? -oldandcoefs[c] : oldandcoefs[c],
               consdata->lhs, consdata->rhs) );
         ++c;
         consdata->changed = TRUE;
         consdata->upgradetried = FALSE;
         consdata->propagated = FALSE;
         consdata->presolved = FALSE;
      }
      else if( compval == +1 )
      {
         assert(!SCIPisZero(scip, andcoefs[c1]));
         assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)res2));
         newconsanddatas[nnewconsanddatas] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2);
         newandcoefs[nnewconsanddatas] = andcoefs[c1];
         newandnegs[nnewconsanddatas] = andnegs[c1];
         ++(newconsanddatas[nnewconsanddatas]->nuses);

         /* add new locks */
         SCIP_CALL( addNewLocks(scip, cons, newconsanddatas[nnewconsanddatas], newandnegs[nnewconsanddatas] ?
               -newandcoefs[nnewconsanddatas] : newandcoefs[nnewconsanddatas], newlhs, newrhs) );
         ++c1;
         consdata->changed = TRUE;
         consdata->upgradetried = FALSE;
         consdata->cliquesadded = FALSE;
         consdata->propagated = FALSE;
         consdata->presolved = FALSE;

         ++nnewconsanddatas;
      }
      else
      {
         SCIP_Bool coefsignchanged;
         SCIP_Bool lhschanged;
         SCIP_Bool rhschanged;

         assert(!SCIPisZero(scip, oldandcoefs[c]));
         assert(!SCIPisZero(scip, andcoefs[c1]));
         assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2) == consanddatas[c]);

         /* copy old consanddata object and new coefficent */
         newconsanddatas[nnewconsanddatas] = consanddatas[c];

         newandcoefs[nnewconsanddatas] = andcoefs[c1];
         newandnegs[nnewconsanddatas] = andnegs[c1];

         if( ((oldandnegs[c] == andnegs[c1]) && !SCIPisEQ(scip, oldandcoefs[c], newandcoefs[c1]))
            || ((oldandnegs[c] != newandnegs[c1]) && !SCIPisEQ(scip, oldandcoefs[c], -newandcoefs[c1])) )
            consdata->upgradetried = FALSE;

         coefsignchanged = (oldandnegs[c] == andnegs[c1]) &&
            ((oldandcoefs[c] < 0 && andcoefs[c1] > 0) || (oldandcoefs[c] > 0 && andcoefs[c1] < 0));
         coefsignchanged = coefsignchanged || ((oldandnegs[c] != andnegs[c1]) &&
            ((oldandcoefs[c] < 0 && andcoefs[c1] < 0) || (oldandcoefs[c] > 0 && andcoefs[c1] > 0)));
         lhschanged = (SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, -newlhs)) || (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisInfinity(scip, -newlhs))
            || (consdata->lhs < 0 && newlhs > 0) || (consdata->lhs > 0 && newlhs < 0);
         rhschanged = (SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, newrhs)) || (!SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, newrhs))
            || (consdata->rhs < 0 && newrhs > 0) || (consdata->rhs > 0 && newrhs < 0);

         /* update or renew locks */
         if( coefsignchanged || lhschanged || rhschanged || newconsanddatas[nnewconsanddatas]->nnewvars > 0)
         {
            /* renew locks */
            SCIP_CALL( removeOldLocks(scip, cons, newconsanddatas[nnewconsanddatas], oldandnegs[c] ?
                  -oldandcoefs[c] : oldandcoefs[c], consdata->lhs, consdata->rhs) );
            SCIP_CALL( addNewLocks(scip, cons, newconsanddatas[nnewconsanddatas], newandnegs[nnewconsanddatas] ?
                  -newandcoefs[nnewconsanddatas] : newandcoefs[nnewconsanddatas], newlhs, newrhs) );

            consdata->changed = TRUE;
            consdata->upgradetried = FALSE;
            consdata->cliquesadded = FALSE;
            consdata->propagated = FALSE;
            consdata->presolved = FALSE;
         }

         ++c;
         ++c1;
         ++nnewconsanddatas;
      }
   }

   /* add all remaining consanddatas and update locks and captures */
   if( c < nconsanddatas )
   {
      assert(c1 == nandress);

      for( ; c < nconsanddatas; ++c )
      {
         SCIP_CONS* andcons;
#ifndef NDEBUG
         SCIP_VAR* res1;

         assert(consanddatas[c] != NULL);
#endif
         andcons = consanddatas[c]->cons;
#ifndef NDEBUG
         if( andcons != NULL )
         {
            res1 = SCIPgetResultantAnd(scip, andcons);
            assert(res1 != NULL);
            assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res1) == consanddatas[c]);
         }
#endif
         if( andcons == NULL )
         {
            consdata->changed = TRUE;
            consdata->upgradetried = FALSE;
            continue;
         }

         assert(consanddatas[c]->nuses > 0);
         --(consanddatas[c]->nuses);

         /* remove old locks */
         SCIP_CALL( removeOldLocks(scip, cons, consanddatas[c], oldandnegs[c] ? -oldandcoefs[c] : oldandcoefs[c],
               consdata->lhs, consdata->rhs) );
         consdata->changed = TRUE;
         consdata->upgradetried = FALSE;
         consdata->propagated = FALSE;
         consdata->presolved = FALSE;
      }
   }
   else if( c1 < nandress )
   {
      for( ; c1 < nandress; ++c1 )
      {
         SCIP_VAR* res2;

         res2 = andress[c1];
         assert(res2 != NULL);
         assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)res2));
         newconsanddatas[nnewconsanddatas] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2);
         newandcoefs[nnewconsanddatas] = andcoefs[c1];
         newandnegs[nnewconsanddatas] = andnegs[c1];
         ++(newconsanddatas[nnewconsanddatas]->nuses);

         /* add new locks */
         SCIP_CALL( addNewLocks(scip, cons, newconsanddatas[nnewconsanddatas], newandnegs[nnewconsanddatas] ?
               -newandcoefs[nnewconsanddatas] : newandcoefs[nnewconsanddatas], newlhs, newrhs) );

         ++nnewconsanddatas;
         consdata->changed = TRUE;
         consdata->upgradetried = FALSE;
         consdata->cliquesadded = FALSE;
         consdata->propagated = FALSE;
         consdata->presolved = FALSE;
      }
   }
   assert(c == nconsanddatas && c1 == nandress);

   /* delete old and-coefficients and consanddata objects */
   SCIPfreeBlockMemoryArray(scip, &(consdata->andcoefs), consdata->sconsanddatas);
   SCIPfreeBlockMemoryArray(scip, &(consdata->andnegs), consdata->sconsanddatas);
   SCIPfreeBlockMemoryArray(scip, &(consdata->consanddatas), consdata->sconsanddatas);

   if( !SCIPisEQ(scip, consdata->lhs, newlhs) || !SCIPisEQ(scip, consdata->rhs, newrhs) )
   {
      consdata->upgradetried = FALSE;
      consdata->lhs = newlhs;
      consdata->rhs = newrhs;
   }

   consdata->consanddatas = newconsanddatas;
   consdata->andcoefs = newandcoefs;
   consdata->andnegs = newandnegs;
   consdata->nconsanddatas = nnewconsanddatas;
   consdata->sconsanddatas = snewconsanddatas;

   oldnvars = consdata->nlinvars;
   /* update number of linear variables without and-resultants */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &(consdata->nlinvars)) );
   consdata->nlinvars -= nnewconsanddatas;

   if( oldnvars != consdata->nlinvars )
   {
      consdata->changed = TRUE;
      consdata->upgradetried = FALSE;
      consdata->cliquesadded = FALSE;
      consdata->propagated = FALSE;
      consdata->presolved = FALSE;
   }

#ifndef NDEBUG
   consanddatas = consdata->consanddatas;
   nconsanddatas = consdata->nconsanddatas;
   assert(consanddatas != NULL || nconsanddatas == 0);

   /* check that consanddata objects are sorted with respect to the problem index of the corresponding resultants */
   for( c = nconsanddatas - 1; c > 0; --c )
   {
      SCIP_VAR* res1;
      SCIP_VAR* res2;
      SCIP_Bool resneg1;
      SCIP_Bool resneg2;
      int resind1;
      int resind2;

      assert(consanddatas[c] != NULL);
      assert(consanddatas[c]->cons != NULL);
      res1 = SCIPgetResultantAnd(scip, consanddatas[c]->cons);
      assert(res1 != NULL);
      assert(consanddatas[c - 1] != NULL);
      assert(consanddatas[c - 1]->cons != NULL);
      res2 = SCIPgetResultantAnd(scip, consanddatas[c - 1]->cons);
      assert(res2 != NULL);
      resneg1 = SCIPvarIsNegated(res1);
      if( resneg1 )
      {
         res1 = SCIPvarGetNegatedVar(res1);
         assert(res1 != NULL);
      }
      resneg2 = SCIPvarIsNegated(res2);
      if( resneg2 )
      {
         res2 = SCIPvarGetNegatedVar(res2);
         assert(res2 != NULL);
      }
      resind1 = SCIPvarGetProbindex(res1);
      resind2 = SCIPvarGetProbindex(res2);
      if( resind1 == -1 && resind2 == -1 )
      {
         resind1 = SCIPvarGetIndex(res1);
         resind2 = SCIPvarGetIndex(res2);
      }

      if( resind1 <= resind2 )
      {
         assert(resind1 == resind2);
         assert(!resneg1);
         assert(resneg2);
      }
   }
#endif

   return SCIP_OKAY;
}

/** adds cliques of the pseudoboolean constraint to the global clique table */
static
SCIP_RETCODE addCliques(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_Bool*const       cutoff,             /**< pointer to store whether the node can be cut off */
   int*const             naggrvars,          /**< pointer to count the number of aggregated variables */
   int*const             nchgbds             /**< pointer to count the number of performed bound changes */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_VAR** vars;
   int nvars;
   SCIP_VAR** linvars;
   SCIP_VAR* andres;
   SCIP_VAR* andres2;
   int nlinvars;
   int nandress;
   int c;
   int v2;
   int v1;
   int nchgbdslocal;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(cutoff != NULL);
   assert(naggrvars != NULL);
   assert(nchgbds != NULL);
   assert(SCIPconsIsActive(cons));

   *cutoff = FALSE;

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   /* if we have no and-constraints left, we should not be here and this constraint should be deleted (only the linaer should survive) */
   assert(consdata->nconsanddatas > 0);

   /* check whether the cliques have already been added */
   if( consdata->cliquesadded )
      return SCIP_OKAY;

   consdata->cliquesadded = TRUE;

   checkConsConsistency(scip, cons);

   /* check standard pointers and sizes */
   assert(consdata->lincons != NULL);
   assert(SCIPconsIsActive(consdata->lincons));
   assert(consdata->linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
   assert(consdata->consanddatas != NULL);
   assert(consdata->nconsanddatas > 0);
   assert(consdata->nconsanddatas <= consdata->sconsanddatas);

   /* check number of linear variables */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
   assert(nvars == consdata->nlinvars + consdata->nconsanddatas);

   /* get temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );

   /* get variables and coefficients */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, NULL, &nvars) );

   /* calculate all not artificial linear variables and all artificial and-resultants
    * @todo should we take into accout the negation status of the cliques?
    */
   SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, NULL, nvars, linvars, NULL, &nlinvars,
         NULL, NULL, NULL, &nandress) );

   assert(nandress == consdata->nconsanddatas);
   assert(consdata->consanddatas != NULL);

   /* find cliques from linear variable to and-resultant */
   for( c = nandress - 1; c >= 0; --c )
   {
      CONSANDDATA* consanddata;
      SCIP_VAR** andvars;
      int nandvars;

      consanddata = consdata->consanddatas[c];
      assert(consanddata != NULL);

      andres = SCIPgetResultantAnd(scip, consanddata->cons);

      /* choose correct variable array */
      if( consanddata->nnewvars > 0 )
      {
         andvars = consanddata->newvars;
         nandvars = consanddata->nnewvars;
      }
      else
      {
         andvars = consanddata->vars;
         nandvars = consanddata->nvars;
      }

      for( v1 = nandvars - 1; v1 >= 0; --v1 )
      {
         SCIP_VAR* var1;
         SCIP_Bool values[2];

         var1 = andvars[v1];
         if( !SCIPvarIsActive(var1) && (!SCIPvarIsNegated(var1) || !SCIPvarIsActive(SCIPvarGetNegationVar(var1))) )
            continue;

         /* get active counterpart to check for common cliques */
         if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED )
         {
            var1 = SCIPvarGetNegationVar(var1);
            values[0] = FALSE;
         }
         else
            values[0] = TRUE;

         for( v2 = nlinvars - 1; v2 >= 0; --v2 )
         {
            SCIP_VAR* var2;

            var2 = linvars[v2];
            if( !SCIPvarIsActive(var2) && (!SCIPvarIsNegated(var2) || !SCIPvarIsActive(SCIPvarGetNegationVar(var2))) )
               continue;

            /* get active counterpart to check for common cliques */
            if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED )
            {
               var2 = SCIPvarGetNegationVar(var2);
               values[1] = FALSE;
            }
            else
               values[1] = TRUE;

            /* if variable in and-constraint1 is the negated variable of a normal linear variable, than we can add a
             * clique between the and-resultant and the normal linear variable, negated variables are not save in
             * cliquetables
             *
             * set r_1 = var1 * z; (z is some product)
             * var1 == ~var2
             *
             * if:
             * var1 + ~var1 <= 1;          r_1
             *    0 +     1 <= 1             0   \
             *    1 +     0 <= 1   ==>  1 or 0    >   ==>    r_1 + var2 <= 1
             *    0 +     0 <= 1             0   /
             */
            if( values[0] != values[1] && var1 == var2 )
            {
               SCIP_CONS* newcons;
               SCIP_VAR* clqvars[2];
               char consname[SCIP_MAXSTRLEN];

               clqvars[0] = andres;
               clqvars[1] = values[1] ? var2 : SCIPvarGetNegatedVar(var2);
               assert(clqvars[1] != NULL);

               /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */

               /* add clique */
               SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
               if( *cutoff )
                  goto TERMINATE;

               *nchgbds += nchgbdslocal;

               (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
               SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
                     SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
                     FALSE, SCIPconsIsPropagated(cons),
                     SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               SCIP_CALL( SCIPaddCons(scip, newcons) );
               SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
               SCIPdebugPrintCons(scip, newcons, NULL);

               SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
            }
            /* if a variable in an and-constraint is in a clique with another normal linear variable, we can add the
             * clique between the linear variable and the and-resultant
             *
             * set r_1 = var1 * z; (z is some product)
             *
             * if:
             * var1 + var2 <= 1;          r_1
             *    0 +    1 <= 1             0   \
             *    1 +    0 <= 1   ==>  1 or 0    >   ==>    r_1 + var2 <= 1
             *    0 +    0 <= 1             0   /
             */
            if( (var1 != var2) && SCIPvarsHaveCommonClique(var1, values[0], var2, values[1], TRUE) )
            {
               SCIP_CONS* newcons;
               SCIP_VAR* clqvars[2];
               char consname[SCIP_MAXSTRLEN];

               clqvars[0] = andres;
               clqvars[1] = values[1] ? var2 : SCIPvarGetNegatedVar(var2);
               assert(clqvars[1] != NULL);

               /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */

               /* add clique */
               SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
               if( *cutoff )
                  goto TERMINATE;

               *nchgbds += nchgbdslocal;

               (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
               SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
                     SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
                     FALSE, SCIPconsIsPropagated(cons),
                     SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               SCIP_CALL( SCIPaddCons(scip, newcons) );
               SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
               SCIPdebugPrintCons(scip, newcons, NULL);

               SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
            }
         }
      }
   }

   /* find cliques over variables which are in different and-constraints */
   for( c = nandress - 1; c > 0; --c )
   {
      CONSANDDATA* consanddata1;
      CONSANDDATA* consanddata2;
      SCIP_VAR** andvars1;
      int nandvars1;
      SCIP_VAR** andvars2;
      int nandvars2;

      consanddata1 = consdata->consanddatas[c];
      assert(consanddata1 != NULL);
      consanddata2 = consdata->consanddatas[c - 1];
      assert(consanddata2 != NULL);

      andres = SCIPgetResultantAnd(scip, consanddata1->cons);
      andres2 = SCIPgetResultantAnd(scip, consanddata2->cons);

      /* choose correct variable array of consanddata object 1 */
      if( consanddata1->nnewvars > 0 )
      {
         andvars1 = consanddata1->newvars;
         nandvars1 = consanddata1->nnewvars;
      }
      else
      {
         andvars1 = consanddata1->vars;
         nandvars1 = consanddata1->nvars;
      }

      /* choose correct variable array of consanddata object 2 */
      if( consanddata2->nnewvars > 0 )
      {
         andvars2 = consanddata2->newvars;
         nandvars2 = consanddata2->nnewvars;
      }
      else
      {
         andvars2 = consanddata2->vars;
         nandvars2 = consanddata2->nvars;
      }

      /* compare both terms for finding new aggregated variables and new cliques */
      for( v1 = nandvars1 - 1; v1 >= 0; --v1 )
      {
         SCIP_VAR* var1;
         SCIP_Bool values[2];

         var1 = andvars1[v1];
         if( !SCIPvarIsActive(var1) && (!SCIPvarIsNegated(var1) || !SCIPvarIsActive(SCIPvarGetNegationVar(var1))) )
            continue;

         /* get active counterpart to check for common cliques */
         if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED )
         {
            var1 = SCIPvarGetNegationVar(var1);
            values[0] = FALSE;
         }
         else
            values[0] = TRUE;

         for( v2 = nandvars2 - 1; v2 >= 0; --v2 )
         {
            SCIP_VAR* var2;

            var2 = andvars2[v2];
            if( !SCIPvarIsActive(var2) && (!SCIPvarIsNegated(var2) || !SCIPvarIsActive(SCIPvarGetNegationVar(var2))) )
               continue;

            /* get active counterpart to check for common cliques */
            if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED )
            {
               var2 = SCIPvarGetNegationVar(var2);
               values[1] = FALSE;
            }
            else
               values[1] = TRUE;

            /* if a variable in and-constraint1 is the negated variable of a variable in and-constraint2, than we can
             * add a clique between both and-resultants, negated variables are not save in cliquetables
             *
             * set r_1 = var1 * z_1; (z_1 is some product)
             * set r_2 = var2 * z_2; (z_2 is some product)
             * var1 == ~var2
             *
             * if:
             * var1 + ~var1 <= 1;          r_1     r_2
             *    0 +     1 <= 1             0  1 or 0   \
             *    1 +     0 <= 1   ==>  1 or 0       0    >   ==>    r_1 + r_2 <= 1
             *    0 +     0 <= 1             0       0   /
             */
            if( values[0] != values[1] && var1 == var2 )
            {
               SCIP_CONS* newcons;
               SCIP_VAR* clqvars[2];
               char consname[SCIP_MAXSTRLEN];

               clqvars[0] = andres;
               clqvars[1] = andres2;

               /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */

               /* add clique */
               SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
               if( *cutoff )
                  goto TERMINATE;

               *nchgbds += nchgbdslocal;

               (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
               SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
                     SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
                     FALSE, SCIPconsIsPropagated(cons),
                     SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               SCIP_CALL( SCIPaddCons(scip, newcons) );
               SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
               SCIPdebugPrintCons(scip, newcons, NULL);

               SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
            }
            /* if a variable in an and-constraint is in a clique with a variable in another and-constraint, we can add
             * the clique between both and-resultant
             *
             * let r_1 = var1 * z_1; (z_1 is some product)
             * let r_2 = var2 * z_2; (z_2 is some product)
             *
             * if:
             * var1 + var2 <= 1;          r_1     r_2
             *    0 +    1 <= 1             0  1 or 0   \
             *    1 +    0 <= 1   ==>  1 or 0       0    >   ==>    r_1 + r_2 <= 1
             *    0 +    0 <= 1             0       0   /
             */
            else if( SCIPvarsHaveCommonClique(var1, values[0], var2, values[1], TRUE) && (var1 != var2) )
            {
               SCIP_CONS* newcons;
               SCIP_VAR* clqvars[2];
               char consname[SCIP_MAXSTRLEN];

               clqvars[0] = andres;
               clqvars[1] = values[1] ? var2 : SCIPvarGetNegatedVar(var2);
               assert(clqvars[1] != NULL);

               /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */

               /* add clique */
               SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
               if( *cutoff )
                  goto TERMINATE;

               *nchgbds += nchgbdslocal;

               (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
               SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
                     SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
                     FALSE, SCIPconsIsPropagated(cons),
                     SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               SCIP_CALL( SCIPaddCons(scip, newcons) );
               SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
               SCIPdebugPrintCons(scip, newcons, NULL);

               SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
            }
         }
      }
   }

 TERMINATE:
   /* free temporary memory */
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &vars);

   return SCIP_OKAY;
}

/** propagation method for pseudoboolean constraints */
static
SCIP_RETCODE propagateCons(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< knapsack constraint */
   SCIP_Bool*const       cutoff,             /**< pointer to store whether the node can be cut off */
   int*const             ndelconss           /**< pointer to count number of deleted constraints */
   )
{
   SCIP_CONSDATA* consdata;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(cutoff != NULL);
   assert(ndelconss != NULL);

   *cutoff = FALSE;

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   assert(consdata->lincons != NULL);

   /* if linear constraint is redundant, than pseudoboolean constraint is redundant too */
   if( SCIPconsIsDeleted(consdata->lincons) )
   {
      SCIP_CALL( SCIPdelConsLocal(scip, cons) );
      ++(*ndelconss);
   }

   /* check if the constraint was already propagated */
   if( consdata->propagated )
      return SCIP_OKAY;

   /* mark the constraint propagated */
   consdata->propagated = TRUE;

   return SCIP_OKAY;
}

/** update and-constraint flags due to pseudoboolean constraint flags */
static
SCIP_RETCODE updateAndConss(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< pseudoboolean constraint */
   )
{
   CONSANDDATA** consanddatas;
   int nconsanddatas;
   SCIP_CONSDATA* consdata;
   int c;

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

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   consanddatas = consdata->consanddatas;
   nconsanddatas = consdata->nconsanddatas;
   assert(consanddatas != NULL || nconsanddatas == 0);

   if( !SCIPconsIsActive(cons) )
      return SCIP_OKAY;

   /* release and-constraints and change check flag of and-constraint */
   for( c = nconsanddatas - 1; c >= 0; --c )
   {
      SCIP_CONS* andcons;

      assert(consanddatas[c] != NULL);

      if( !consanddatas[c]->istransformed )
         continue;

      andcons = consanddatas[c]->cons;
      assert(andcons != NULL);

      SCIP_CALL( SCIPsetConsChecked(scip, andcons, SCIPconsIsChecked(cons)) );
   }

   return SCIP_OKAY;
}

/** delete unused information in constraint handler data */
static
SCIP_RETCODE correctConshdlrdata(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   int*const             ndelconss           /**< pointer to count number of deleted constraints */
   )
{
   CONSANDDATA** allconsanddatas;
   CONSANDDATA* consanddata;
   SCIP_VAR** fixedvars = SCIPgetFixedVars(scip);
   SCIP_VAR** activevars;
   SCIP_Real* activescalars;
   SCIP_Real activeconstant;
   int nvars = SCIPgetNVars(scip);
   int nfixedvars = SCIPgetNFixedVars(scip);
   int c;

   assert(scip != NULL);
   assert(conshdlrdata != NULL);
   assert(ndelconss != NULL);

   if( conshdlrdata->nallconsanddatas == 0 )
      return SCIP_OKAY;

   allconsanddatas = conshdlrdata->allconsanddatas;
   assert(allconsanddatas != NULL);
   assert(conshdlrdata->nallconsanddatas >= 1);
   assert(conshdlrdata->nallconsanddatas <= conshdlrdata->sallconsanddatas);

   if( nfixedvars >= 1 && nvars >= 1 )
   {
      SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &activescalars, nvars) );
   }
   else
   {
      activevars = NULL;
      activescalars = NULL;
   }

   for( c = conshdlrdata->nallconsanddatas - 1; c >= 0; --c )
   {
      SCIP_VAR** tmpvars;
      int stmpvars;
      SCIP_CONS* cons;
      int v;

      consanddata = allconsanddatas[c];

      assert(consanddata->nvars == 0 || (consanddata->vars != NULL && consanddata->svars > 0));
      assert(consanddata->nnewvars == 0 || (consanddata->newvars != NULL && consanddata->snewvars > 0));

      if( !consanddata->istransformed )
      {
         assert(consanddata->vars == NULL || consanddata->origcons != NULL);
         assert(consanddata->nvars == 0 || consanddata->origcons != NULL);
         assert(consanddata->svars == 0 || consanddata->origcons != NULL);
         assert(consanddata->newvars == NULL);
         assert(consanddata->nnewvars == 0);
         assert(consanddata->snewvars == 0);

         continue;
      }

      /* if no variables are left, delete variables arrays */
      if( consanddata->nvars == 0 )
      {
         SCIP_VAR* resvar = SCIPgetResultantAnd(scip, consanddata->cons);

         /* if we have no old variables, than also no new variables */
         assert(consanddata->nnewvars == 0);
         assert(consanddata->nuses > 0);
         assert(resvar != NULL);

         /* delete and-constraint */
         SCIP_CALL( SCIPdelCons(scip, consanddata->cons) );
         ++(*ndelconss);

         SCIP_CALL( transformToOrig(scip, consanddata, conshdlrdata) );

         consanddata->nuses = 0;

         /* remove consanddata from hashtable, if it existed only in transformed space */
         if( consanddata->origcons == NULL )
         {
            assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
            SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddata) );
         }
         assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)resvar));
         SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)resvar) );

         /* unlock upgrade to provide control */
         SCIPconsAddUpgradeLocks(consanddata->cons, -1);

         /* release and-constraint */
         SCIP_CALL( SCIPreleaseCons(scip, &consanddata->cons) );

         continue;
      }

      /* the consanddata object is not used anymore, so extract the and constraint and delete other data */
      if( consanddata->nuses == 0 )
      {
         SCIP_Bool looseorcolumn;
         SCIP_VARSTATUS varstatus;

         if( consanddata->cons == NULL )
         {
            assert(!consanddata->istransformed || consanddata->noriguses > 0);
            assert((consanddata->noriguses > 0) == (consanddata->origcons != NULL));
            assert(consanddata->vars == NULL || consanddata->origcons != NULL);
            assert(consanddata->nvars == 0 || consanddata->origcons != NULL);
            assert(consanddata->svars == 0 || consanddata->origcons != NULL);
            assert(consanddata->newvars == NULL);
            assert(consanddata->nnewvars == 0);
            assert(consanddata->snewvars == 0);

            continue;
         }

         SCIP_CALL( transformToOrig(scip, consanddata, conshdlrdata) );

         varstatus = SCIPvarGetStatus(SCIPgetResultantAnd(scip, consanddata->cons));
         looseorcolumn = (varstatus == SCIP_VARSTATUS_LOOSE || varstatus == SCIP_VARSTATUS_COLUMN);

         /* @note due to aggregations or fixings the resultant may need to be propagated later on, so we can only
          *       delete the and-constraint if the resultant is of column or loose status
          *       and is not an active variable of another (multi-)aggregated/negated variable
          */
         if( looseorcolumn )
         {
            SCIP_VAR* resvar = SCIPgetResultantAnd(scip, consanddata->cons);
            SCIP_Bool del = TRUE;
            int w;

            assert(nvars >= 1);

            /* we need to check all active representatives */
            for( w = 0; w < nfixedvars && del; ++w )
            {
               int nactivevars;
               int requiredsize;
               int i;

               assert(fixedvars != NULL);
               assert(activevars != NULL);
               assert(activescalars != NULL);
               activevars[0] = fixedvars[w];
               activescalars[0] = 1.0;
               activeconstant = 0.0;
               nactivevars = 1;
               SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activescalars, &nactivevars, nvars, &activeconstant, &requiredsize) );
               assert(requiredsize == nactivevars);

               for( i = 0; i < nactivevars && del; ++i )
               {
                  assert(SCIPvarGetStatus(activevars[i]) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(activevars[i]) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(activevars[i]) == SCIP_VARSTATUS_FIXED);

                  if( activevars[i] == resvar )
                     del = FALSE;
               }
            }

            if( del )
            {
               SCIP_CALL( SCIPdelCons(scip, consanddata->cons) );
            }
         }

         if( !SCIPconsIsDeleted(consanddata->cons) )
         {
            /* change flags */
            if( !looseorcolumn )
            {
               SCIP_CALL( SCIPsetConsInitial(scip, consanddata->cons, FALSE) );
            }
            SCIP_CALL( SCIPsetConsChecked(scip, consanddata->cons, TRUE) );
         }

         /* remove consanddata from hashtable, if it existed only in transformed space */
         if( consanddata->origcons == NULL )
         {
            assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
            SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddata) );
         }
         assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->cons)));
         SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->cons)) );

         /* unlock upgrade to provide control */
         SCIPconsAddUpgradeLocks(consanddata->cons, -1);

         /* release and-constraint */
         SCIP_CALL( SCIPreleaseCons(scip, &consanddata->cons) );
         ++(*ndelconss);

         continue;
      }

      cons = consanddata->cons;
      assert(cons != NULL);

      /* if and-constraint is deleted, delete variables arrays */
      if( SCIPconsIsDeleted(cons) )
      {
         SCIP_VAR* resvar = SCIPgetResultantAnd(scip, consanddata->cons);

         assert(consanddata->nuses > 0);
         assert(resvar != NULL);

         SCIP_CALL( transformToOrig(scip, consanddata, conshdlrdata) );

         /* release and-constraint */
         consanddata->nuses = 0;

         /* remove consanddata from hashtable, if it existed only in transformed space */
         if( consanddata->origcons == NULL )
         {
            assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
            SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddata) );
         }
         assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)resvar));
         SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)resvar) );

         /* unlock upgrade to provide control */
         SCIPconsAddUpgradeLocks(consanddata->cons, -1);

         /* release and-constraint */
         SCIP_CALL( SCIPreleaseCons(scip, &consanddata->cons) );

         continue;
      }

      /* if no new variables exist, we do not need to do anything here */
      if( consanddata->nnewvars == 0 )
         continue;

      tmpvars = consanddata->vars;
      /* release all variables */
      for( v = consanddata->nvars - 1; v >= 0; --v )
      {
         /* in original problem the variables was already deleted */
         assert(tmpvars[v] != NULL);
         SCIP_CALL( SCIPreleaseVar(scip, &tmpvars[v]) );
      }

      /* exchange newvars with old vars array */
      tmpvars = consanddata->vars;
      stmpvars = consanddata->svars;
      consanddata->vars = consanddata->newvars;
      consanddata->svars = consanddata->snewvars;
      consanddata->nvars = consanddata->nnewvars;
      consanddata->newvars = tmpvars;
      consanddata->snewvars = stmpvars;
      /* reset number of variables in newvars array */
      consanddata->nnewvars = 0;
   }

   if( activevars != NULL )
   {
      SCIPfreeBufferArray(scip, &activescalars);
      SCIPfreeBufferArray(scip, &activevars);
   }

   return SCIP_OKAY;
}

/** update the uses counter of consandata objects which are used in pseudoboolean constraint, that were deleted and
 *  probably delete and-constraints
 */
static
SCIP_RETCODE updateConsanddataUses(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   int*const             ndelconss           /**< pointer to store number of deleted constraints */
   )
{
   CONSANDDATA** consanddatas;
   int nconsanddatas;
   SCIP_CONSDATA* consdata;
   int c;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlrdata != NULL);
   assert(ndelconss != NULL);

   /* can only be called when constraint was deleted */
   assert(SCIPconsIsDeleted(cons));

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   consanddatas = consdata->consanddatas;
   nconsanddatas = consdata->nconsanddatas;
   assert(nconsanddatas > 0 && consanddatas != NULL);
   assert(consdata->andcoefs != NULL);

   /* remove old locks */
   for( c = nconsanddatas - 1; c >= 0; --c )
   {
      CONSANDDATA* consanddata;

      consanddata = consanddatas[c];
      assert(consanddata != NULL);

      if( !consanddata->istransformed )
         continue;

      SCIP_CALL( removeOldLocks(scip, cons, consanddata, consdata->andcoefs[c], consdata->lhs, consdata->rhs) );
   }

   /* correct consandata usage counters and data */
   for( c = nconsanddatas - 1; c >= 0; --c )
   {
      CONSANDDATA* consanddata;

      consanddata = consanddatas[c];
      assert(consanddata != NULL);
      assert(consanddatas[c]->istransformed);

      assert(consanddata->nuses > 0);

      if( consanddata->nuses > 0 )
         --(consanddata->nuses);

      /* if data object is not used anymore, delete it */
      if( consanddata->nuses == 0 )
      {
         SCIP_VAR* resvar;
         SCIP_VARSTATUS varstatus;
         SCIP_Bool looseorcolumn;

         SCIP_CALL( transformToOrig(scip, consanddata, conshdlrdata) );

         resvar = SCIPgetResultantAnd(scip, consanddata->cons);
         assert(resvar != NULL);

         varstatus = SCIPvarGetStatus(resvar);
         looseorcolumn = (varstatus == SCIP_VARSTATUS_LOOSE || varstatus == SCIP_VARSTATUS_COLUMN);

         /* @note due to aggregations or fixings the resultant may need to be propagated later on, so we can only
          *       delete the and-constraint if the resultant is of column or loose status
          *       and is not an active variable of another (multi-)aggregated/negated variable
          */
         if( looseorcolumn )
         {
            /* we can only delete and constraints if the resultant is an artificial variable and also active, because
             * then the assigned value is not of interest and the artificial and constraint does not need to be
             * fulfilled
             *
             * if this variable is not such an artificial variable we need the IRRELEVANT vartype which should be the
             * correct way to fix this
             */

            assert(!SCIPconsIsChecked(consanddata->cons));
            SCIP_CALL( SCIPdelCons(scip, consanddata->cons) );
         }

         if( !SCIPconsIsDeleted(consanddata->cons) )
         {
            /* change flags */
            if( !looseorcolumn )
            {
               SCIP_CALL( SCIPsetConsInitial(scip, consanddata->cons, FALSE) );
            }
            SCIP_CALL( SCIPsetConsChecked(scip, consanddata->cons, TRUE) );
         }

         /* remove consanddata from hashtable, if it existed only in transformed space */
         if( consanddata->origcons == NULL )
         {
            assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
            SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddata) );
         }
         assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->cons)));
         SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->cons)) );

         /* unlock upgrade to provide control */
         SCIPconsAddUpgradeLocks(consanddata->cons, -1);

         /* release and-constraint */
         SCIP_CALL( SCIPreleaseCons(scip, &consanddata->cons) );
         ++(*ndelconss);
      }
   }

   consdata->nconsanddatas = 0;

   return SCIP_OKAY;
}


/* maximal number to enumerate solutions for one pseudoboolean constraint to check for an upgrade to an XOR constraint */
#define MAXNVARS 10 /* note that this cannot be bigger than 31 */

/** calculate result for a given pseudoboolean constraint with given values, this is used to decide whether a
 *  pseudoboolean constraint can be upgrade to an XOR constraint
 */
static
SCIP_RETCODE checkSolution(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_VAR**const       vars,               /**< all variables which occur */
   int const             nvars,              /**< number of all variables which appear in the pseudoboolean
                                              *   constraint
                                              */
   SCIP_Bool*const       values,             /**< values of all variables which appear in the pseudoboolean
                                              *   constraint
                                              */
   SCIP_VAR**const       linvars,            /**< linear variables */
   SCIP_Real*const       lincoefs,           /**< linear coefficients */
   int const             nlinvars,           /**< number of linear variables */
   SCIP_Real const       constant,           /**< offset to the linear part */
   SCIP_Real const       side,               /**< side of pseudoboolean constraint */
   CONSANDDATA**const    consanddatas,       /**< all consanddata objects in a constraint */
   SCIP_Real*const       consanddatacoefs,   /**< nonlinear coefficients */
   SCIP_Bool*const       consanddatanegs,    /**< negation status of and resultants in pseudo-boolean constraint */
   int const             nconsanddatas,      /**< number of all consanddata objects */
   int const             cnt,                /**< number of variables set to 1 */
   int*const             xortype             /**< pointer to save the possible xor type if a solution was valid and does
                                              *   not violate the old xortype
                                              */
   )
{
   CONSANDDATA* consanddata;
   SCIP_VAR** termvars;
   SCIP_VAR** repvars;
   int ntermvars;
   SCIP_Bool* negated;
   SCIP_Real value;
   int pos;
   int v;
   int c;

   assert(scip != NULL);
   assert(vars != NULL);
   assert(nvars > 0);
   assert(values != NULL);
   assert(linvars != NULL || nlinvars == 0);
   assert(lincoefs != NULL || nlinvars == 0);
   assert(nvars >= nlinvars);
   assert(SCIPisEQ(scip, side, 1.0) || SCIPisZero(scip, side));
   assert(consanddatas != NULL);
   assert(consanddatacoefs != NULL);
   assert(nconsanddatas > 0);
   assert(*xortype >= -1 && *xortype <= 1);

   /* order the variables after index, to compare them easier */
   SCIPsortPtr((void**)linvars, SCIPvarCompActiveAndNegated, nlinvars);
   SCIPsortPtr((void**)vars, SCIPvarCompActiveAndNegated, nvars);

   value = constant;
   for( v = nlinvars - 1; v >= 0; --v )
   {
      if( SCIPsortedvecFindPtr((void**)vars, SCIPvarCompActiveAndNegated, linvars[v], nvars, &pos) ) /*lint !e613*/
      {
         if( values[pos] )
            value += lincoefs[v]; /*lint !e613*/
      }
      else
      {
         /* this cannot happen, all linear variables should be a part of 'vars' */
         SCIPABORT();

         *xortype = -1;  /*lint !e527*/
         return SCIP_OKAY;
      }
   }

   SCIP_CALL( SCIPallocBufferArray(scip, &repvars, MAXNVARS) );
   SCIP_CALL( SCIPallocBufferArray(scip, &negated, MAXNVARS) );

   for( c = nconsanddatas - 1; c >= 0; --c )
   {
      SCIP_Bool val = TRUE;

      consanddata = consanddatas[c];
      assert(consanddata != NULL);
      assert(consanddata->istransformed);

      /* choose correct variable array to add locks for, we only add locks for now valid variables */
      if( consanddata->nnewvars > 0 )
      {
         termvars = consanddata->newvars;
         ntermvars = consanddata->nnewvars;
      }
      else
      {
         termvars = consanddata->vars;
         ntermvars = consanddata->nvars;
      }
      assert(ntermvars > 0 && termvars != NULL);

      BMSclearMemoryArray(negated, MAXNVARS);

      /* get linear active representation */
      SCIP_CALL( SCIPgetBinvarRepresentatives(scip, ntermvars, termvars, repvars, negated) );
      SCIPsortPtrBool((void**)repvars, negated, SCIPvarCompActiveAndNegated, ntermvars);

      for( v = ntermvars - 1; v >= 0; --v )
      {
         SCIP_VAR* var;

         assert(!negated[v] || (SCIPvarIsNegated(repvars[v]) && SCIPvarGetNegatedVar(repvars[v]) != NULL));

         var = ( negated[v] ? SCIPvarGetNegationVar(repvars[v]) : repvars[v]);
         if( SCIPsortedvecFindPtr((void**)vars, SCIPvarCompActiveAndNegated, var, nvars, &pos) )
         {
            if( (negated[v] && values[pos]) || (!negated[v] && !values[pos]) )
            {
               val = FALSE;
               break;
            }
         }
         else
         {
            /* this cannot happen, all non-linear variables should be a part of 'vars' */
            SCIPABORT();

            *xortype = -1; /*lint !e527*/
            goto TERMINATE;
         }
      }

      if( val != consanddatanegs[c] )
         value += consanddatacoefs[c];
   }

   if( SCIPisEQ(scip, value, side) )
   {
      /* first solution is checked, so determine the possible xor upgrade */
      if( *xortype == -1 )
      {
         if( cnt % 2 == 0 )
            *xortype = 0;
         else
            *xortype = 1;
      }
      /* check if this solution does not fit in all possible xor solutions */
      else if( *xortype == 1 && cnt % 2 == 0 )
         *xortype = -1;
      else if( *xortype == 0 && cnt % 2 == 1 )
         *xortype = -1;
   }
   else
   {
      /* first not-solution is checked, so determine the possible xor upgrade */
      if( *xortype == -1 )
      {
         if( cnt % 2 == 0 )
            *xortype = 1;
         else
            *xortype = 0;
      }
      /* check if this had to be a solution for an upgrade to an xor */
      else if( *xortype == 1 && cnt % 2 == 1 )
         *xortype = -1;
      else if( *xortype == 0 && cnt % 2 == 0 )
         *xortype = -1;
   }

 TERMINATE:
   SCIPfreeBufferArray(scip, &negated);
   SCIPfreeBufferArray(scip, &repvars);

   return SCIP_OKAY;
}

/** try upgrading pseudoboolean linear constraint to an XOR constraint and/or remove possible and-constraints
 *
 *  @note An XOR(x_1,..,x_n) = 1 <=> XOR(x1,..,~x_j,..,x_n) = 0, for j in {1,..,n}, which is not yet checked while
 *        trying to upgrade
 */
static
SCIP_RETCODE tryUpgradingXor(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   int*const             ndelconss,          /**< pointer to store number of deleted constraints */
   int*const             naddconss,          /**< pointer to count number of added constraints */
   int*const             nfixedvars,         /**< pointer to store number of fixed variables */
   int*const             nchgcoefs,          /**< pointer to store number of changed coefficients constraints */
   int*const             nchgsides,          /**< pointer to store number of changed sides constraints */
   SCIP_Bool*const       cutoff              /**< pointer to store if a cutoff happened */
   )
{
   SCIP_CONSDATA* consdata;
   CONSANDDATA** consanddatas;
   int nconsanddatas;
   CONSANDDATA* consanddata;
   SCIP_VAR** allvars;
   SCIP_Real* allcoefs;
   int nallvars;
   SCIP_VAR** linvars;
   SCIP_Real* lincoefs;
   int nlinvars;
   SCIP_Real* andcoefs;
   SCIP_Bool* andnegs;
   int nandress;
   SCIP_VAR** vars;
   int nvars;
   SCIP_VAR** repvars;
   SCIP_Bool* negated;
   SCIP_VAR** activelinvars;
   SCIP_Bool* values;
   SCIP_CONS* lincons;
   SCIP_CONS* newcons;
   char newname[SCIP_MAXSTRLEN];
   SCIP_Real constant;
   int requiredsize;
   int firstnlinvars;
   int oldnlinvars;
   int xortype;
   int v;
   int v1;
   int c;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlrdata != NULL);
   assert(ndelconss != NULL);
   assert(nfixedvars != NULL);
   assert(nchgcoefs != NULL);
   assert(nchgsides != NULL);
   assert(cutoff != NULL);
   assert(SCIPconsIsActive(cons));

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   consanddatas = consdata->consanddatas;
   andcoefs = consdata->andcoefs;
   andnegs = consdata->andnegs;
   nconsanddatas = consdata->nconsanddatas;
   assert(nconsanddatas > 0 && consanddatas != NULL);

   assert(consdata->lincons != NULL);
   assert(consdata->linconstype == SCIP_LINEARCONSTYPE_LINEAR || consdata->linconstype == SCIP_LINEARCONSTYPE_SETPPC);

   /* only equations can be updated */
   if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) || (!SCIPisEQ(scip, consdata->lhs, 1.0) && !SCIPisZero(scip, consdata->lhs)) )
      return SCIP_OKAY;

   assert(consanddatas[0] != NULL);
   assert(consanddatas[0]->cons != NULL);

   lincons = consdata->lincons;

   /* check number of linear variables */
   SCIP_CALL( getLinearConsNVars(scip, lincons, consdata->linconstype, &nallvars) );
   assert(nallvars - nconsanddatas == consdata->nlinvars);
   nlinvars = consdata->nlinvars;

   if( nlinvars > MAXNVARS )
      return SCIP_OKAY;

   checkConsConsistency(scip, cons);

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &allvars, nallvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &allcoefs, nallvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvars, MAXNVARS) );
   SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, MAXNVARS) );
   SCIP_CALL( SCIPallocBufferArray(scip, &repvars, MAXNVARS) );
   SCIP_CALL( SCIPallocBufferArray(scip, &negated, MAXNVARS) );

   /* get variables and coefficients */
   SCIP_CALL( getLinearConsVarsData(scip, lincons, consdata->linconstype, allvars, allcoefs, &nallvars) );
   assert(nallvars > 0);

   /* calculate all not artificial linear variables */
   SCIP_CALL( getLinVarsAndAndRess(scip, cons, allvars, allcoefs, nallvars, linvars, lincoefs, &nlinvars,
         NULL, NULL, NULL, &nandress) );
   assert(nlinvars == consdata->nlinvars);
   assert(nandress == nallvars-nlinvars);

   constant = 0;

   /* get linear active representation */
   SCIP_CALL( SCIPgetProbvarLinearSum(scip, linvars, lincoefs, &nlinvars, MAXNVARS, &constant, &requiredsize) );
   assert(requiredsize == nlinvars);
   SCIP_CALL( SCIPduplicateBufferArray(scip, &activelinvars, linvars, nlinvars) );

   if( requiredsize > MAXNVARS )
      goto TERMINATE;

   firstnlinvars = nlinvars;

   /* order the variables after index, to compare them easier */
   SCIPsortPtr((void**)linvars, SCIPvarCompActiveAndNegated, nlinvars);

   for( c = nconsanddatas - 1; c >= 0; --c )
   {
      consanddata = consanddatas[c];
      assert(consanddata != NULL);
      assert(consanddata->istransformed);

      /* choose correct variable array */
      if( consanddata->nnewvars > 0 )
      {
         vars = consanddata->newvars;
         nvars = consanddata->nnewvars;
      }
      else
      {
         vars = consanddata->vars;
         nvars = consanddata->nvars;
      }
      assert(nvars > 0 && vars != NULL);

      if( nvars > MAXNVARS )
         goto TERMINATE;

      BMSclearMemoryArray(negated, MAXNVARS);

      /* get linear active representation */
      SCIP_CALL( SCIPgetBinvarRepresentatives(scip, nvars, vars, repvars, negated) );
      SCIPsortPtr((void**)repvars, SCIPvarCompActiveAndNegated, nvars);

      oldnlinvars = nlinvars;

      /* determine all different variables over the linear variables and all variables in all and constraints */
      for( v = nvars - 1, v1 = nlinvars - 1; v >= 0 && v1 >= 0; )
      {
         SCIP_VAR* var;

         /* it appears that some fixed variables were not yet deleted */
         if( SCIPvarGetLbGlobal(repvars[v]) > 0.5 || SCIPvarGetUbGlobal(repvars[v]) < 0.5 )
            goto TERMINATE;

         assert(SCIPvarIsActive(linvars[v1]));
         assert(SCIPvarIsActive(repvars[v]) || (SCIPvarIsNegated(repvars[v]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v]))));

         if( SCIPvarIsActive(repvars[v]) )
            var = repvars[v];
         else
            var = SCIPvarGetNegationVar(repvars[v]);

         if( SCIPvarGetIndex(var) > SCIPvarGetIndex(linvars[v1]) )
         {
            if( nlinvars + 1 < MAXNVARS )
            {
               linvars[nlinvars] = var;
               ++nlinvars;
            }
            else
               goto TERMINATE;

            --v;
         }
         else if( SCIPvarGetIndex(var) < SCIPvarGetIndex(linvars[v1]) )
            --v1;
         else
         {
            --v;
            --v1;
         }
      }

      /* add the rest of variables */
      if( v >= 0 )
      {
         SCIP_VAR* var;

         for( ; v >= 0; --v )
         {
            /* it appears that some fixed variables were not yet deleted */
            if( SCIPvarGetLbGlobal(repvars[v]) > 0.5 || SCIPvarGetUbGlobal(repvars[v]) < 0.5 )
               goto TERMINATE;

            assert(SCIPvarIsActive(repvars[v]) || (SCIPvarIsNegated(repvars[v]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v]))));

            if( SCIPvarIsActive(repvars[v]) )
               var = repvars[v];
            else
               var = SCIPvarGetNegationVar(repvars[v]);

            if( nlinvars + 1 < MAXNVARS )
            {
               linvars[nlinvars] = var;
               ++nlinvars;
            }
            else
               goto TERMINATE;
         }
      }

      /* if some new variables were inserted we need to reorder the array */
      if( nlinvars > oldnlinvars )
      {
         /* order the variables after index, to compare them easier */
         SCIPsortPtr((void**)linvars, SCIPvarCompActiveAndNegated, nlinvars);
      }
   }

   SCIP_CALL( SCIPallocBufferArray(scip, &values, nlinvars) );
   xortype = -1;

   /* check values for variables which result in solutions which in the end lead to an XOR upgrade */
   for( v = (1 << nlinvars) - 1; v >= 0; --v ) /*lint !e701*/
   {
      int cnt = 0;
      for( v1 = nlinvars - 1; v1 >= 0; --v1 )
         if( v & (1 << v1) ) /*lint !e701*/
         {
            values[v1] = TRUE;
            ++cnt;
         }
         else
            values[v1] = FALSE;

      /* at maximum nlinvars values could be set to TRUE */
      assert(cnt <= nlinvars);

      SCIP_CALL( checkSolution(scip, linvars, nlinvars, values, activelinvars, lincoefs, firstnlinvars, constant,
            consdata->lhs, consanddatas, andcoefs, andnegs, nconsanddatas, cnt, &xortype) );
      if( xortype == -1 )
         break;
   }

   SCIPfreeBufferArray(scip, &values);

   assert(xortype >= -1 && xortype <= 1);

   if( xortype >= 0 )
   {
      (void) SCIPsnprintf(newname, SCIP_MAXSTRLEN, "%s_upgraded", SCIPconsGetName(lincons));

      SCIP_CALL( SCIPcreateConsXor(scip, &newcons, newname, (SCIP_Bool) xortype, nlinvars, linvars,
            SCIPconsIsInitial(lincons), SCIPconsIsSeparated(lincons), SCIPconsIsEnforced(lincons), SCIPconsIsChecked(lincons),
            SCIPconsIsPropagated(lincons), SCIPconsIsLocal(lincons), SCIPconsIsModifiable(lincons),
            SCIPconsIsDynamic(lincons), SCIPconsIsRemovable(lincons), SCIPconsIsStickingAtNode(lincons)) );

      /* add and release new constraint */
      SCIP_CALL( SCIPaddCons(scip, newcons) );

      SCIPdebugMsg(scip, "created upgraded XOR constraint:\n");
      SCIPdebugMsg(scip, "old -> ");
      SCIPdebugPrintCons(scip, lincons, NULL);
      SCIPdebugMsg(scip, "new -> ");
      SCIPdebugPrintCons(scip, newcons, NULL);

      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
      ++(*naddconss);

      /* delete old constraints */
      SCIP_CALL( SCIPdelCons(scip, lincons) );
      SCIP_CALL( SCIPdelCons(scip, cons) );
      (*ndelconss) += 2;
   }

 TERMINATE:
   /* delete temporary memory */
   SCIPfreeBufferArray(scip, &activelinvars);
   SCIPfreeBufferArray(scip, &negated);
   SCIPfreeBufferArray(scip, &repvars);
   SCIPfreeBufferArray(scip, &lincoefs);
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &allcoefs);
   SCIPfreeBufferArray(scip, &allvars);

   return SCIP_OKAY;
}

/** try upgrading pseudoboolean logicor constraint to a linear constraint and/or remove possible and-constraints */
static
SCIP_RETCODE tryUpgradingLogicor(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   int*const             ndelconss,          /**< pointer to store number of deleted constraints */
   int*const             naddconss,          /**< pointer to count number of added constraints */
   int*const             nfixedvars,         /**< pointer to store number of fixed variables */
   int*const             nchgcoefs,          /**< pointer to store number of changed coefficients constraints */
   int*const             nchgsides,          /**< pointer to store number of changed sides constraints */
   SCIP_Bool*const       cutoff              /**< pointer to store if a cutoff happened */
   )
{
   CONSANDDATA** consanddatas;
   int nconsanddatas;
   SCIP_CONSDATA* consdata;
   int c;
   int v;
   int v2;
   SCIP_VAR** eqvars;
   int neqvars;
   int nminvars;
   int nmaxvars;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlrdata != NULL);
   assert(ndelconss != NULL);
   assert(nfixedvars != NULL);
   assert(nchgcoefs != NULL);
   assert(nchgsides != NULL);
   assert(cutoff != NULL);
   assert(SCIPconsIsActive(cons));

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   consanddatas = consdata->consanddatas;
   nconsanddatas = consdata->nconsanddatas;
   assert(nconsanddatas > 0 && consanddatas != NULL);

   assert(consdata->lincons != NULL);
   assert(consdata->linconstype == SCIP_LINEARCONSTYPE_LOGICOR);

   assert(consanddatas[0] != NULL);
   assert(consanddatas[0]->cons != NULL);

   if( nconsanddatas == 1 )
   {
      CONSANDDATA* consanddata;
      SCIP_VAR** allvars;
      SCIP_Real* allcoefs;
      int nallvars;
      SCIP_VAR** linvars;
      SCIP_Real* lincoefs;
      int nlinvars;
      SCIP_VAR** vars;
      int nvars;
      SCIP_CONS* lincons;
      SCIP_CONS* newcons;
      char newname[SCIP_MAXSTRLEN];
      SCIP_Real lhs;
      SCIP_Real rhs;

      /* if we have only one term left in the logicor constraint, the presolving should be done by the logicor
       * constraint handler
       */
      if( consdata->nlinvars == 0 )
      {
         return SCIP_OKAY;
      }

      /* for every old logicor constraint: sum_i (x_i) + res >= 1 , with an and-constraint of res as the resultant,
       *     which looks like 'res = y_1 * ... * y_n' => sum_i (n * x_i) + sum_j=1^n y_j >= n
       *
       * i.e. x_1 +  x_2 +  x_3 + x_4 * x_5 * x_6 >= 1
       *  => 3x_1 + 3x_2 + 3x_3 + x_4 + x_5 + x_6 >= 3
       */

      lincons = consdata->lincons;

      consanddata = consanddatas[0];
      assert(consanddata != NULL);
      assert(consanddata->istransformed);

      /* choose correct variable array to add locks for, we only add locks for now valid variables */
      if( consanddata->nnewvars > 0 )
      {
         vars = consanddata->newvars;
         nvars = consanddata->nnewvars;
      }
      else
      {
         vars = consanddata->vars;
         nvars = consanddata->nvars;
      }
      assert(nvars > 0 && vars != NULL);

      lhs = nvars;
      rhs = SCIPinfinity(scip);

      (void) SCIPsnprintf(newname, SCIP_MAXSTRLEN, "%s_upgraded", SCIPconsGetName(lincons));

      SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, newname, 0, NULL, NULL, lhs, rhs,
            SCIPconsIsInitial(lincons), SCIPconsIsSeparated(lincons), SCIPconsIsEnforced(lincons), SCIPconsIsChecked(lincons),
            SCIPconsIsPropagated(lincons), SCIPconsIsLocal(lincons), SCIPconsIsModifiable(lincons),
            SCIPconsIsDynamic(lincons), SCIPconsIsRemovable(lincons), SCIPconsIsStickingAtNode(lincons)) );

      /* check number of linear variables */
      SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nallvars) );
      assert(nallvars == consdata->nlinvars + 1);

      nlinvars = consdata->nlinvars;

      /* allocate temporary memory */
      SCIP_CALL( SCIPallocBufferArray(scip, &allvars, nallvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &allcoefs, nallvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nlinvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nlinvars) );

      /* get variables and coefficients */
      SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, allvars, allcoefs, &nallvars) );
      assert(allcoefs != NULL);

      /* calculate all not artificial linear variables */
      SCIP_CALL( getLinVarsAndAndRess(scip, cons, allvars, allcoefs, nallvars, linvars, lincoefs, &nlinvars,
            NULL, NULL, NULL, NULL) );
      assert(nlinvars == consdata->nlinvars);

      /* add linear part to new constraint */
      for( v = 0; v < nlinvars; ++v )
      {
         SCIP_CALL( SCIPaddCoefLinear(scip, newcons, linvars[v], (SCIP_Real) nvars) );
      }

      /* add non-linear part to new constraint */
      for( v = 0; v < nvars; ++v )
      {
         SCIP_CALL( SCIPaddCoefLinear(scip, newcons, vars[v], 1.0) );
      }

      /* add and release new constraint */
      SCIP_CALL( SCIPaddCons(scip, newcons) );

      SCIPdebugMsg(scip, "created upgraded linear constraint:\n");
      SCIPdebugMsg(scip, "old -> ");
      SCIPdebugPrintCons(scip, lincons, NULL);
      SCIPdebugMsg(scip, "new -> ");
      SCIPdebugPrintCons(scip, newcons, NULL);

      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
      ++(*naddconss);

      /* delete old constraints */
      SCIP_CALL( SCIPdelCons(scip, lincons) );
      SCIP_CALL( SCIPdelCons(scip, cons) );
      (*ndelconss) += 2;

      /* delete temporary memory */
      SCIPfreeBufferArray(scip, &lincoefs);
      SCIPfreeBufferArray(scip, &linvars);
      SCIPfreeBufferArray(scip, &allcoefs);
      SCIPfreeBufferArray(scip, &allvars);

      return SCIP_OKAY;
   }

   /* initializing array for variables which can appear in all consanddata objects */
   c = nconsanddatas - 1;
   assert(consanddatas[c]->istransformed);

   /* choose correct variable array */
   if( consanddatas[c]->nnewvars > 0 )
   {
      neqvars = consanddatas[c]->nnewvars;
      /* allocate temporary memory */
      SCIP_CALL( SCIPduplicateBufferArray(scip, &eqvars, consanddatas[c]->newvars, neqvars) );
   }
   else
   {
      neqvars = consanddatas[c]->nvars;
      /* allocate temporary memory */
      SCIP_CALL( SCIPduplicateBufferArray(scip, &eqvars, consanddatas[c]->vars, neqvars) );
   }
   nminvars = neqvars;
   nmaxvars = neqvars;
   assert(neqvars > 0 && eqvars != NULL);

#ifndef NDEBUG
   /* check that variables are sorted */
   for( v = neqvars - 1; v > 0; --v )
      assert(SCIPvarGetIndex(eqvars[v]) > SCIPvarGetIndex(eqvars[v - 1]));
#endif
   /* computing all variables which appear in all consanddata objects */
   for( --c ; c >= 0; --c )
   {
      CONSANDDATA* consanddata;
      SCIP_VAR** vars;
      int nvars;
      int nneweqvars;

      consanddata = consanddatas[c];
      assert(consanddata != NULL);
      assert(consanddatas[c]->istransformed);

      /* choose correct variable array to add locks for, we only add locks for now valid variables */
      if( consanddata->nnewvars > 0 )
      {
         vars = consanddata->newvars;
         nvars = consanddata->nnewvars;
      }
      else
      {
         vars = consanddata->vars;
         nvars = consanddata->nvars;
      }
      assert(nvars > 0 && vars != NULL);

#ifndef NDEBUG
      /* check that variables are sorted */
      for( v = nvars - 1; v > 0; --v )
         assert(SCIPvarGetIndex(vars[v]) > SCIPvarGetIndex(vars[v - 1]));
#endif

      /* update minimal number of variables in and-constraint */
      if( nvars < nminvars )
         nminvars = nvars;
      /* update maximal number of variables in and-constraint */
      else if( nvars > nmaxvars )
         nmaxvars = nvars;
      assert(nminvars > 0);
      assert(nminvars <= nmaxvars);

      nneweqvars = 0;
      for( v = 0, v2 = 0; v < neqvars && v2 < nvars; )
      {
         int index1;
         int index2;

         assert(eqvars[v] != NULL);
         assert(vars[v2] != NULL);
         index1 = SCIPvarGetIndex(eqvars[v]);
         index2 = SCIPvarGetIndex(vars[v2]);

         /* check which variables are still in all and-constraints */
         if( index1 < index2 )
            ++v;
         else if( index1 > index2 )
            ++v2;
         else
         {
            assert(index1 == index2);
            assert(nneweqvars <= v);

            if( nneweqvars < v )
               eqvars[nneweqvars] = eqvars[v];
            ++nneweqvars;
            ++v;
            ++v2;
         }
      }
      neqvars = nneweqvars;

      /* now we only want to handle the easy case where nminvars == neqvars + 1
       * @todo: implement for the othercase too
       */
      if( nminvars > neqvars + 1 )
         break;

      /* if no variables overlap we have to stop */
      if( neqvars == 0 )
         break;
   }

   /* if all and-constraints in pseudoboolean constraint have some equal variables we can extract them and create a new
    * linear constraint; iff the number of equal variables is equal to the number of variables - 1 in all consanddata
    * objects then the new constraint will not contain any products; if no normal linear variables exist we can fix all
    * equal variables to 1
    *
    * e.g. x1 * x2 + x1 * x3 + x1 * x4 >= 1
    * =>   x1 = 1 /\ x2 + x3 + x4 >= 1
    *
    * e.g. x1 * x2 * x3 + x1 * x2 * x4 + x5 >= 1
    * =>  2x1 + 2x2 + x3 + x4 + 5x5 >= 5
    *
    * e.g. x1 * x2 * x3 + x1 * x4 >= 1
    * =>   x1 = 1 /\ x2 * x3 + x4 >= 1 (constraint is created indirectly, caused by the fixing of x1)
    *
    * @todo: implement the next cases
    *
    * e.g. x1 * x2 * x3 + x1 * x4 + x5 >= 1
    * =>  2x1 + x2 * x3 + x4 + 3x5 >= 3 (x2 * x3 will be a new and-constraint)
    *
    * e.g. x1 * x2 + x1 * x2 * x3 + x4 >= 1
    * =>  x1 + x2 + 2x4 >= 2
    *
    * e.g. x1 * x2 + x1 * x3 + x2 * x3 + sum_i x_i >= 1
    * =>  x1 + x2 + x3 + 2 * sum_i x_i >= 2
    *
    */

   /* Extract additional information ???
    *
    * e.g. x1 * x2 * x4 + x1 * x3 * x5 + x2 * x3 * x6 >= 1
    * =>  extract x1 + x2 + x3 >= 2
    */

   /* if we have no normal linear variable in the logicor constraint, we can fix all equal variables */
   if( neqvars > 0 && consdata->nlinvars == 0 )
   {
      SCIP_Bool infeasible;
      SCIP_Bool fixed;

      /* fix all equal variable in logicor constraints which have to be one to fulfill the constraint */
      for( v = 0; v < neqvars; ++v )
      {
         /* fix the variable which cannot be one */
         SCIP_CALL( SCIPfixVar(scip, eqvars[v], 1.0, &infeasible, &fixed) );
         if( infeasible )
         {
            SCIPdebugMsg(scip, " -> infeasible fixing\n");
            *cutoff = TRUE;
            goto TERMINATE;
         }
         if( fixed )
            ++(*nfixedvars);
      }

      /* if a complete consanddata object have all variables in common with all other consanddata objects, than we can
       * delete this constraint after fixing all equal variables
       */
      if( nminvars == neqvars )
      {
         /* delete old constraints */
         SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
         SCIP_CALL( SCIPdelCons(scip, cons) );
         (*ndelconss) += 2;

         goto TERMINATE;
      }
   }

   /* now the following condition grant us that we can linearize the whole constraint */
   if( neqvars > 0 && nminvars == nmaxvars && nminvars == neqvars + 1 )
   {
      SCIP_CONS* lincons;
      SCIP_CONS* newcons;
      char newname[SCIP_MAXSTRLEN];
      SCIP_Real lhs;
      SCIP_Real rhs;

      lhs = 1.0;
      rhs = SCIPinfinity(scip);

      lincons = consdata->lincons;

      (void) SCIPsnprintf(newname, SCIP_MAXSTRLEN, "%s_upgraded", SCIPconsGetName(lincons));

      SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, newname, 0, NULL, NULL, lhs, rhs,
            SCIPconsIsInitial(lincons), SCIPconsIsSeparated(lincons), SCIPconsIsEnforced(lincons), SCIPconsIsChecked(lincons),
            SCIPconsIsPropagated(lincons), SCIPconsIsLocal(lincons), SCIPconsIsModifiable(lincons),
            SCIPconsIsDynamic(lincons), SCIPconsIsRemovable(lincons), SCIPconsIsStickingAtNode(lincons)) );

      /* if createcons == TRUE add all variables which are not in the eqvars array to the new constraint with
       * coefficient 1.0
       */
      for( c = nconsanddatas - 1; c >= 0; --c )
      {
         CONSANDDATA* consanddata;
         SCIP_VAR** vars;
         int nvars;

         consanddata = consanddatas[c];
         assert(consanddata != NULL);
         assert(consanddatas[c]->istransformed);

         /* choose correct variable array to add locks for, we only add locks for now valid variables */
         if( consanddata->nnewvars > 0 )
         {
            vars = consanddata->newvars;
            nvars = consanddata->nnewvars;
         }
         else
         {
            vars = consanddata->vars;
            nvars = consanddata->nvars;
         }
         assert(nvars > 0 && vars != NULL);

         for( v = 0, v2 = 0; v < neqvars && v2 < nvars; )
         {
            int index1;
            int index2;

            assert(eqvars[v] != NULL);
            assert(vars[v2] != NULL);
            index1 = SCIPvarGetIndex(eqvars[v]);
            index2 = SCIPvarGetIndex(vars[v2]);

            /* all variables in eqvars array must exist in all and-constraints */
            assert(index1 >= index2);

            if( index1 > index2 )
            {
               SCIP_CALL( SCIPaddCoefLinear(scip, newcons, vars[v2], 1.0) );
               ++v2;
            }
            else
            {
               assert(index1 == index2);
               ++v;
               ++v2;
            }
         }

         /* if we did not loop over all variables in the and-constraint, go on and fix variables */
         if( v2 < nvars )
         {
            assert(v == neqvars);
            for( ; v2 < nvars; ++v2)
            {
               SCIP_CALL( SCIPaddCoefLinear(scip, newcons, vars[v2], 1.0) );
            }
         }
         assert(v == neqvars && v2 == nvars);
      }

      /* if we have normal linear variable in the logicor constraint, we did not fix all equal variables and we have to
       * add them with a coefficient of 'nconsanddatas'
       * we have to add also all normal linear variables with a coefficient of 'nconsanddatas * neqvars + 1'
       */
      if( consdata->nlinvars > 0 )
      {
         SCIP_VAR** vars;
         SCIP_Real* coefs;
         int nvars;
         SCIP_VAR** linvars;
         SCIP_Real* lincoefs;
         int nlinvars;

         /* add all equal variables */
         for( v = 0; v < neqvars; ++v )
         {
            SCIP_CALL( SCIPaddCoefLinear(scip, newcons, eqvars[v], (SCIP_Real)nconsanddatas) );
         }

         /* check number of linear variables */
         SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
         assert(nvars == consdata->nlinvars + consdata->nconsanddatas);

         /* allocate temporary memory */
         SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
         SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
         SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );
         SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nvars) );

         /* get variables and coefficients */
         SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
         assert(coefs != NULL || nvars == 0);

#ifndef NDEBUG
         /* all coefficients have to be 1 */
         for( v = 0; v < nvars; ++v )
            assert(SCIPisEQ(scip, coefs[v], 1.0));
#endif
         /* calculate all not artificial linear variables */
         SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars,
               NULL, NULL, NULL, NULL) );
         assert(nlinvars == consdata->nlinvars);

         /* add all old normal linear variables */
         for( v = 0; v < nlinvars; ++v )
         {
            SCIP_CALL( SCIPaddCoefLinear(scip, newcons, linvars[v], (SCIP_Real)(nconsanddatas * neqvars + 1)) ); /*lint !e732 !e790*/
         }

         /* reset left hand side to correct value */
         SCIP_CALL( SCIPchgLhsLinear(scip, newcons, (SCIP_Real)(nconsanddatas * neqvars + 1)) ); /*lint !e732 !e790*/

         /* free temporary memory */
         SCIPfreeBufferArray(scip, &lincoefs);
         SCIPfreeBufferArray(scip, &linvars);
         SCIPfreeBufferArray(scip, &coefs);
         SCIPfreeBufferArray(scip, &vars);
      }

      /* add and release new constraint */
      SCIP_CALL( SCIPaddCons(scip, newcons) );

      SCIPdebugMsg(scip, "created upgraded linear constraint:\n");
      SCIPdebugMsg(scip, "old -> ");
      SCIPdebugPrintCons(scip, lincons, NULL);
      SCIPdebugMsg(scip, "new -> ");
      SCIPdebugPrintCons(scip, newcons, NULL);

      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
      ++(*naddconss);

      /* delete old constraints */
      SCIP_CALL( SCIPdelCons(scip, lincons) );
      SCIP_CALL( SCIPdelCons(scip, cons) );
      (*ndelconss) += 2;
   }

 TERMINATE:
   /* free temporary memory */
   SCIPfreeBufferArray(scip, &eqvars);

   return SCIP_OKAY;
}

/** try upgrading pseudoboolean setppc constraint to a linear constraint and/or remove possible and-constraints */
static
SCIP_RETCODE tryUpgradingSetppc(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   int*const             ndelconss,          /**< pointer to store number of deleted constraints */
   int*const             naddconss,          /**< pointer to count number of added constraints */
   int*const             nfixedvars,         /**< pointer to store number of fixed variables */
   int*const             nchgcoefs,          /**< pointer to store number of changed coefficients constraints */
   int*const             nchgsides,          /**< pointer to store number of changed sides constraints */
   SCIP_Bool*const       cutoff              /**< pointer to store if a cutoff happened */
   )
{
   CONSANDDATA** consanddatas;
   int nconsanddatas;
   SCIP_CONSDATA* consdata;
   SCIP_SETPPCTYPE type;
   int c;
   int v;
   int v2;
   SCIP_VAR** eqvars;
   int neqvars;
   int nminvars;
   int nmaxvars;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlrdata != NULL);
   assert(ndelconss != NULL);
   assert(nfixedvars != NULL);
   assert(nchgcoefs != NULL);
   assert(nchgsides != NULL);
   assert(cutoff != NULL);
   assert(SCIPconsIsActive(cons));

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   consanddatas = consdata->consanddatas;
   nconsanddatas = consdata->nconsanddatas;
   assert(nconsanddatas > 0 && consanddatas != NULL);

   assert(consdata->lincons != NULL);
   assert(consdata->linconstype == SCIP_LINEARCONSTYPE_SETPPC);

   type = SCIPgetTypeSetppc(scip, consdata->lincons);

   switch( type )
   {
   case SCIP_SETPPCTYPE_PARTITIONING:
   case SCIP_SETPPCTYPE_PACKING:
      break;
   case SCIP_SETPPCTYPE_COVERING:
      return SCIP_OKAY;
   default:
      SCIPerrorMessage("unknown setppc type\n");
      return SCIP_INVALIDDATA;
   }

   assert(consanddatas[0] != NULL);
   assert(consanddatas[0]->cons != NULL);

   if( nconsanddatas == 1 )
   {
      /* if we have only one term left in the setppc constraint, the presolving should be done by the setppc constraint handler */
      if( consdata->nlinvars == 0 )
      {
         return SCIP_OKAY;
      }

      /* @todo: implement the following */

      /* for each set packing constraint:
       *     sum_i (x_i) + res <= 1 , with and-constraint of res as the resultant like res = y_1 * ... * y_n
       *  => sum_i (n * x_i) + sum_j=1^n y_j <= n + n-1
       *
       * i.e. x_1 + x_2 + x_3 + x_4*x_5*x_6 <= 1
       *  => 3x_1 + 3x_2 + 3x_3 + x_4 + x_5 + x_6 <= 5
       */

      /* for each set partitioning constraint:
       *     sum_i (x_i) + res = 1 , with the corresponding and-constraint of res like
       *                             res = y_1 * ... * y_n
       *
       *  => n <= sum_i (n * x_i) + sum_j=1^n y_j <= 2 * n - 1
       *
       * i.e. x_1 + x_2 + x_3 + x_4*x_5*x_6 = 1
       *  => 3 <= 3x_1 + 3x_2 + 3x_3 + x_4 + x_5 + x_6 <= 5
       *
       */

      return SCIP_OKAY;
   }

   if( consdata->nlinvars > 0 )
   {
      /* @todo: */
      return SCIP_OKAY;
   }
   assert(consdata->nlinvars == 0 && nconsanddatas > 1);

   c = nconsanddatas - 1;
   assert(consanddatas[c]->istransformed);

   /* initializing array for variables which can appear in all consanddata objects */
   if( consanddatas[c]->nnewvars > 0 )
   {
      neqvars = consanddatas[c]->nnewvars;
      /* allocate temporary memory */
      SCIP_CALL( SCIPduplicateBufferArray(scip, &eqvars, consanddatas[c]->newvars, neqvars) );
   }
   else
   {
      neqvars = consanddatas[c]->nvars;
      /* allocate temporary memory */
      SCIP_CALL( SCIPduplicateBufferArray(scip, &eqvars, consanddatas[c]->vars, neqvars) );
   }
   nminvars = neqvars;
   nmaxvars = neqvars;
   assert(neqvars > 0 && eqvars != NULL);

#ifndef NDEBUG
   /* check that variables are sorted */
   for( v = neqvars - 1; v > 0; --v )
      assert(SCIPvarGetIndex(eqvars[v]) > SCIPvarGetIndex(eqvars[v - 1]));
#endif

   for( --c ; c >= 0; --c )
   {
      CONSANDDATA* consanddata;
      SCIP_VAR** vars;
      int nvars;
      int nneweqvars;

      consanddata = consanddatas[c];
      assert(consanddata != NULL);
      assert(consanddatas[c]->istransformed);

      /* choose correct variable array to add locks for, we only add locks for now valid variables */
      if( consanddata->nnewvars > 0 )
      {
         vars = consanddata->newvars;
         nvars = consanddata->nnewvars;
      }
      else
      {
         vars = consanddata->vars;
         nvars = consanddata->nvars;
      }
      assert(nvars > 0 && vars != NULL);

#ifndef NDEBUG
      /* check that variables are sorted */
      for( v = nvars - 1; v > 0; --v )
         assert(SCIPvarGetIndex(vars[v]) > SCIPvarGetIndex(vars[v - 1]));
#endif

      /* update minimal number of variables in and-constraint */
      if( nvars < nminvars )
         nminvars = nvars;
      /* update maximal number of variables in and-constraint */
      else if( nvars > nmaxvars )
         nmaxvars = nvars;
      assert(nminvars > 0);
      assert(nminvars <= nmaxvars);

      nneweqvars = 0;
      for( v = 0, v2 = 0; v < neqvars && v2 < nvars; )
      {
         int index1;
         int index2;

         assert(eqvars[v] != NULL);
         assert(vars[v2] != NULL);
         index1 = SCIPvarGetIndex(eqvars[v]);
         index2 = SCIPvarGetIndex(vars[v2]);

         /* check which variables are still in all and-constraints */
         if( index1 < index2 )
            ++v;
         else if( index1 > index2 )
            ++v2;
         else
         {
            assert(index1 == index2);
            assert(nneweqvars <= v);

            if( nneweqvars < v )
               eqvars[nneweqvars] = eqvars[v];
            ++nneweqvars;
            ++v;
            ++v2;
         }
      }
      neqvars = nneweqvars;

      /* now we only want to handle the easy case where nminvars == neqvars + 1
       * @todo: implement for the othercase too
       */
      if( nminvars > neqvars + 1 && type != SCIP_SETPPCTYPE_PARTITIONING)
         break;

      if( neqvars == 0 )
         break;
   }

   /* if all and-constraints in pseudoboolean constraint have the same length and some equal variables we can upgrade
    * the linear constraint and fix some variables in setpartitioning case
    *
    * e.g. x1 * x2 + x1 * x3 + x1 * x4 <= 1
    * =>  3x1 + x2 + x3 + x4 <= 4
    *
    * e.g. x1 * x2 * x3 + x1 * x2 * x4 <= 1
    * =>  2x1 + 2x2 + x3 + x4 <= 5
    *
    * e.g. x1 * x2 + x1 * x2 * x3 + x1 * x2 * x4 <= 1
    * =>  3x1 + 3x2 + x3 + x4 <= 6
    *
    * e.g. x1 * x2 + x1 * x3 == 1
    * =>   x1 = 1 /\ x2 + x3 == 1
    *
    * e.g. x1 * x2 * x3 + x1 * x4 == 1
    * =>   x1 = 1 /\ x2 * x3 + x4 == 1 (constraint is created indirectly, caused by the fixing of x1)
    *
    * e.g. x1 * x2 + x1 * x2 * x3 + x1 * x2 * x4 == 1
    * =>   x1 = 1, x2 = 1, x3 = 0, x4 = 0
    *
    * e.g. x1 * x2 + x1 * x2 * x3 + x1 * x2 * x4 * x5 == 1
    * =>   x1 = 1, x2 = 1, x3 = 0 /\ x4 * x5 == 0
    *
    * @todo: implement the next cases
    *
    * e.g. x1 * x2 * x3 + x1 * x2 * x4 + x5 <= 1
    * =>  2x1 + 2x2 + x3 + x4 + x5 <= 5
    *
    */
   if( neqvars > 0 && ((nminvars == nmaxvars && nminvars == neqvars + 1) || (nminvars == neqvars) || (type == SCIP_SETPPCTYPE_PARTITIONING)) )
   {
      SCIP_CONS* lincons;
      SCIP_CONS* newcons;
      char newname[SCIP_MAXSTRLEN];
      SCIP_Real lhs;
      SCIP_Real rhs;
      SCIP_Bool infeasible;
      SCIP_Bool fixed;
      SCIP_Bool createcons;
      SCIP_Bool deletecons;

      newcons = NULL;

      /* determine new sides of linear constraint */
      if( type == SCIP_SETPPCTYPE_PARTITIONING )
      {
         lhs = 1.0;
         rhs = 1.0;
      }
      else
      {
         assert(type == SCIP_SETPPCTYPE_PACKING);
         lhs = -SCIPinfinity(scip);
         rhs = 1.0;
      }

      /* if one and-constraint was completely contained in all other and-constraints, we have to reduced the right hand
       * side by 1
       */
      if( neqvars == nminvars )
         rhs -= 1.0;

      createcons = (SCIPisLE(scip, lhs, rhs) && ((nminvars == nmaxvars && nminvars == neqvars + 1) || (nminvars == neqvars)));
      assert(createcons || type == SCIP_SETPPCTYPE_PARTITIONING);

      deletecons = (type == SCIP_SETPPCTYPE_PARTITIONING && nminvars == neqvars);

      lincons = consdata->lincons;

      if( createcons )
      {
         (void) SCIPsnprintf(newname, SCIP_MAXSTRLEN, "%s_upgraded", SCIPconsGetName(lincons));

         SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, newname, 0, NULL, NULL, lhs, rhs,
               SCIPconsIsInitial(lincons), SCIPconsIsSeparated(lincons), SCIPconsIsEnforced(lincons), SCIPconsIsChecked(lincons),
               SCIPconsIsPropagated(lincons), SCIPconsIsLocal(lincons), SCIPconsIsModifiable(lincons),
               SCIPconsIsDynamic(lincons), SCIPconsIsRemovable(lincons), SCIPconsIsStickingAtNode(lincons)) );
      }

      /* if createcons == TRUE add all variables which are not in the eqvars array to the new constraint with
       * coefficient 1.0
       *
       * otherwise (if createcons == FALSE) fix all variables to zero which are not in the eqvars array and if we have a
       * set partitioning constraint
       */
      for( c = nconsanddatas - 1; c >= 0; --c )
      {
         CONSANDDATA* consanddata;
         SCIP_VAR** vars;
         int nvars;

         consanddata = consanddatas[c];
         assert(consanddata != NULL);
         assert(consanddatas[c]->istransformed);

         /* choose correct variable array to add locks for, we only add locks for now valid variables */
         if( consanddata->nnewvars > 0 )
         {
            vars = consanddata->newvars;
            nvars = consanddata->nnewvars;
         }
         else
         {
            vars = consanddata->vars;
            nvars = consanddata->nvars;
         }
         assert(nvars > 0 && vars != NULL);

         /* if the consanddata object has at least two more different variables then the equal variables we have to fix the resultant to zero */
         if( deletecons && neqvars + 1 < nvars )
         {
            assert(SCIPgetResultantAnd(scip, consanddata->cons) != NULL);

            /* fix the resultant variable which have to be zero */
            SCIP_CALL( SCIPfixVar(scip, SCIPgetResultantAnd(scip, consanddata->cons), 0.0, &infeasible, &fixed) );
            if( infeasible )
            {
               SCIPdebugMsg(scip, " -> infeasible fixing\n");
               *cutoff = TRUE;
               goto TERMINATE;
            }
            if( fixed )
               ++(*nfixedvars);

            continue;
         }

         /* if the consanddata object has at exactly one more different variable then the equal variables we have to fix it to zero */
         for( v = 0, v2 = 0; v < neqvars && v2 < nvars; )
         {
            int index1;
            int index2;

            assert(eqvars[v] != NULL);
            assert(vars[v2] != NULL);
            index1 = SCIPvarGetIndex(eqvars[v]);
            index2 = SCIPvarGetIndex(vars[v2]);

            /* all variables in eqvars array must exist in all and-constraints */
            assert(index1 >= index2);

            if( index1 > index2 )
            {
               if( createcons )
               {
                  assert(newcons != NULL);
                  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, vars[v2], 1.0) );
               }
               else if( deletecons )
               {
                  /* fix the variable which cannot be one */
                  SCIP_CALL( SCIPfixVar(scip, vars[v2], 0.0, &infeasible, &fixed) );
                  if( infeasible )
                  {
                     SCIPdebugMsg(scip, " -> infeasible fixing\n");
                     *cutoff = TRUE;
                     goto TERMINATE;
                  }
                  if( fixed )
                     ++(*nfixedvars);
               }
               ++v2;
            }
            else
            {
               assert(index1 == index2);

               ++v;
               ++v2;
            }
         }

         /* if we did not loop over all variables in the and-constraint, go on and fix variables */
         if( v2 < nvars )
         {
            assert(v == neqvars);
            for( ; v2 < nvars; ++v2)
            {
               if( createcons )
               {
                  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, vars[v2], 1.0) );
               }
               else if( deletecons )
               {
                  /* fix the variable which cannot be one */
                  SCIP_CALL( SCIPfixVar(scip, vars[v2], 0.0, &infeasible, &fixed) );
                  if( infeasible )
                  {
                     SCIPdebugMsg(scip, " -> infeasible fixing\n");
                     *cutoff = TRUE;
                     goto TERMINATE;
                  }
                  if( fixed )
                     ++(*nfixedvars);
               }
            }
         }
         assert(v == neqvars && v2 == nvars);
      }

      /* fix all equal variable in set-partitioning constraints which have to be one, in set-packing constraint we have
       * to add these variable with a coeffcient as big as (nconsanddatas - 1)
       */
      for( v = 0; v < neqvars; ++v )
      {
         if( type == SCIP_SETPPCTYPE_PARTITIONING )
         {
            /* fix the variable which have to be one */
            SCIP_CALL( SCIPfixVar(scip, eqvars[v], 1.0, &infeasible, &fixed) );
            if( infeasible )
            {
               SCIPdebugMsg(scip, " -> infeasible fixing\n");
               *cutoff = TRUE;
               goto TERMINATE;
            }
            if( fixed )
               ++(*nfixedvars);
         }
         else
         {
            assert(type == SCIP_SETPPCTYPE_PACKING);
            SCIP_CALL( SCIPaddCoefLinear(scip, newcons, eqvars[v], (SCIP_Real)(nconsanddatas - 1)) );
         }
      }

      /* correct right hand side for set packing constraint */
      if( type == SCIP_SETPPCTYPE_PACKING )
      {
         assert(createcons);
         assert(newcons != NULL);

         SCIP_CALL( SCIPchgRhsLinear(scip, newcons, rhs + (SCIP_Real)((nconsanddatas - 1) * neqvars)) ); /*lint !e790*/
      }

      /* add and release new constraint */
      if( createcons )
      {
         SCIP_CALL( SCIPaddCons(scip, newcons) );

         SCIPdebugMsg(scip, "created upgraded linear constraint:\n");
         SCIPdebugMsg(scip, "old -> ");
         SCIPdebugPrintCons(scip, lincons, NULL);
         SCIPdebugMsg(scip, "new -> ");
         SCIPdebugPrintCons(scip, newcons, NULL);

         SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
         ++(*naddconss);

         assert(!deletecons);
         deletecons = TRUE;
      }

      if( deletecons )
      {
         /* delete old constraints */
         SCIP_CALL( SCIPdelCons(scip, lincons) );
         SCIP_CALL( SCIPdelCons(scip, cons) );
         (*ndelconss) += 2;
      }
   }

 TERMINATE:
   /* free temporary memory */
   SCIPfreeBufferArray(scip, &eqvars);

   return SCIP_OKAY;
}

/** try upgrading pseudoboolean constraint to a linear constraint and/or remove possible and-constraints */
static
SCIP_RETCODE tryUpgrading(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   int*const             ndelconss,          /**< pointer to store number of upgraded constraints */
   int*const             naddconss,          /**< pointer to count number of added constraints */
   int*const             nfixedvars,         /**< pointer to store number of fixed variables */
   int*const             nchgcoefs,          /**< pointer to store number of changed coefficients constraints */
   int*const             nchgsides,          /**< pointer to store number of changed sides constraints */
   SCIP_Bool*const       cutoff              /**< pointer to store if a cutoff happened */
   )
{
   SCIP_CONSDATA* consdata;
   int nvars;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlrdata != NULL);
   assert(ndelconss != NULL);
   assert(nfixedvars != NULL);
   assert(nchgcoefs != NULL);
   assert(nchgsides != NULL);
   assert(cutoff != NULL);
   assert(SCIPconsIsActive(cons));

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   assert(consdata->lincons != NULL);

   /* if no consanddata-objects in pseudoboolean constraint are left, create the corresponding linear constraint */
   if( consdata->nconsanddatas == 0 )
   {
      SCIPconsAddUpgradeLocks(consdata->lincons, -1);

      /* @todo: maybe it is better to create everytime a standard linear constraint instead of letting the special
       *        linear constraint stay
       */
      SCIP_CALL( SCIPdelCons(scip, cons) );
      ++(*ndelconss);

      return SCIP_OKAY;
   }

   assert(consdata->consanddatas != NULL);

   /* check number of linear variables */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
   assert(consdata->nlinvars + consdata->nconsanddatas == nvars);

   switch( consdata->linconstype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      SCIP_CALL( tryUpgradingXor(scip, cons, conshdlrdata, ndelconss, naddconss, nfixedvars, nchgcoefs, nchgsides, cutoff) );
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
      SCIP_CALL( tryUpgradingLogicor(scip, cons, conshdlrdata, ndelconss, naddconss, nfixedvars, nchgcoefs, nchgsides, cutoff) );
      break;
   case SCIP_LINEARCONSTYPE_KNAPSACK:
      break;
   case SCIP_LINEARCONSTYPE_SETPPC:
      SCIP_CALL( tryUpgradingSetppc(scip, cons, conshdlrdata, ndelconss, naddconss, nfixedvars, nchgcoefs, nchgsides, cutoff) );
      if( !SCIPconsIsDeleted(cons) )
      {
         SCIP_CALL( tryUpgradingXor(scip, cons, conshdlrdata, ndelconss, naddconss, nfixedvars, nchgcoefs, nchgsides, cutoff) );
      }
      break;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
      SCIP_CALL( tryUpgradingXor(scip, cons, conshdlrdata, ndelconss, naddconss, nfixedvars, nchgcoefs, nchgsides, cutoff) );
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   if( SCIPconsIsDeleted(cons) )
   {
      /* update the uses counter of consandata objects which are used in pseudoboolean constraint, which was deleted and
       * probably delete and-constraints
       */
      SCIP_CALL( updateConsanddataUses(scip, cons, conshdlrdata, ndelconss) );
   }

   consdata->upgradetried = TRUE;

   return SCIP_OKAY;
}

/** check if we can aggregated some variables */
static
SCIP_RETCODE findAggregation(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONSHDLRDATA*const conshdlrdata,     /**< pseudoboolean constraint handler data */
   int*const             ndelconss,          /**< pointer to store number of upgraded constraints */
   int*const             naggrvars,          /**< pointer to store number of aggregated variables */
   SCIP_Bool*const       cutoff              /**< pointer to store if a cutoff happened */
   )
{
   CONSANDDATA** consanddatas;
   SCIP_CONSDATA* consdata;
   SCIP_VAR** allvars;
   int* varcount[2];
   SCIP_VAR** repvars;
   SCIP_Bool* negated;
   SCIP_VAR** vars;
   int nconsanddatas;
   int nvars;
   int zerocount;
   int onecount;
   int twocount;
   int othercount;
   int c;
   int v;
   int i;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlrdata != NULL);
   assert(ndelconss != NULL);
   assert(naggrvars != NULL);
   assert(cutoff != NULL);
   assert(SCIPconsIsActive(cons));

   if( SCIPconsIsModifiable(cons) )
      return SCIP_OKAY;

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   assert(consdata->lincons != NULL);

   consanddatas = consdata->consanddatas;
   nconsanddatas = consdata->nconsanddatas;
   assert(consanddatas != NULL || nconsanddatas == 0);

   /* we have only one special case for aggregations, a set-partinioning constraint */
   if( consdata->linconstype != SCIP_LINEARCONSTYPE_SETPPC || SCIPgetTypeSetppc(scip, consdata->lincons) != SCIP_SETPPCTYPE_PARTITIONING )
      return SCIP_OKAY;

   assert(SCIPisEQ(scip, consdata->rhs, consdata->lhs));
   assert(SCIPisEQ(scip, consdata->rhs, 1.0));

   if( nconsanddatas < 2 || nconsanddatas > 3 )
      return SCIP_OKAY;

#ifndef NDEBUG
   /* check number of linear variables */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
   assert(consdata->nlinvars + nconsanddatas == nvars);
#endif

   if( consdata->nlinvars != 1 )
      return SCIP_OKAY;

   /* check valid number of variables */
   if( consanddatas[0]->nnewvars > 0 )
      nvars = consanddatas[0]->nnewvars;
   else
      nvars = consanddatas[0]->nvars;

   if( consanddatas[1]->nnewvars > 0 )
   {
      if( nvars != consanddatas[1]->nnewvars )
         return SCIP_OKAY;
   }
   else if( nvars != consanddatas[1]->nvars )
      return SCIP_OKAY;

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &allvars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &(varcount[0]), nvars) );
   BMSclearMemoryArray(varcount[0], nvars);
   SCIP_CALL( SCIPallocBufferArray(scip, &(varcount[1]), nvars) );
   BMSclearMemoryArray(varcount[1], nvars);

   SCIP_CALL( SCIPallocBufferArray(scip, &repvars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &negated, nvars) );
   BMSclearMemoryArray(negated, nvars);

   /* get valid variables */
   if( consanddatas[nconsanddatas - 1]->nnewvars > 0 )
      vars = consanddatas[nconsanddatas - 1]->newvars;
   else
      vars = consanddatas[nconsanddatas - 1]->vars;

   /* get linear active representation */
   SCIP_CALL( SCIPgetBinvarRepresentatives(scip, nvars, vars, repvars, negated) );
   SCIPsortPtrBool((void**)repvars, negated, SCIPvarCompActiveAndNegated, nvars);

#ifndef NDEBUG
   /* and-constraints have to be merged in order to check for aggregation */
   for( v = 1; v < nvars; ++v )
   {
      SCIP_VAR* var1;
      SCIP_VAR* var2;

      /* it appears that some fixed variables were not yet deleted */
      if( SCIPvarGetLbGlobal(repvars[v-1]) > 0.5 || SCIPvarGetUbGlobal(repvars[v-1]) < 0.5 )
         goto TERMINATE;

      /* it appears that some fixed variables were not yet deleted */
      if( SCIPvarGetLbGlobal(repvars[v]) > 0.5 || SCIPvarGetUbGlobal(repvars[v]) < 0.5 )
         goto TERMINATE;

      assert(SCIPvarIsActive(repvars[v]) || (SCIPvarIsNegated(repvars[v]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v]))));
      assert(SCIPvarIsActive(repvars[v-1]) || (SCIPvarIsNegated(repvars[v-1]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v-1]))));
      assert(SCIPvarIsActive(repvars[v]) != negated[v]);
      assert(SCIPvarIsActive(repvars[v-1]) != negated[v-1]);

      var1 = (negated[v-1] ? SCIPvarGetNegationVar(repvars[v-1]) : repvars[v-1]);
      var2 = (negated[v] ? SCIPvarGetNegationVar(repvars[v]) : repvars[v]);
      assert(var1 != var2);
   }
#endif

   /* initializing the statuses of all appearing variables */
   for( v = nvars - 1; v >= 0; --v )
   {
      /* it appears that some fixed variables were not yet deleted */
      if( SCIPvarGetLbGlobal(repvars[v]) > 0.5 || SCIPvarGetUbGlobal(repvars[v]) < 0.5 )
         goto TERMINATE;

      assert(SCIPvarIsActive(repvars[v]) || (SCIPvarIsNegated(repvars[v]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v]))));
      assert(SCIPvarIsActive(repvars[v]) != negated[v]);

      allvars[v] = negated[v] ? SCIPvarGetNegationVar(repvars[v]) : repvars[v];

      ++(varcount[negated[v]][v]);
   }

   for( c = nconsanddatas - 2; c >= 0; --c )
   {
      int pos = -1;

      /* get valid variables */
      if( consanddatas[nconsanddatas - 1]->nnewvars > 0 )
         vars = consanddatas[c]->newvars;
      else
         vars = consanddatas[c]->vars;

      /* need to reset the negated flags */
      BMSclearMemoryArray(negated, nvars);

      /* get linear active representation */
      SCIP_CALL( SCIPgetBinvarRepresentatives(scip, nvars, vars, repvars, negated) );
      SCIPsortPtrBool((void**)repvars, negated, SCIPvarCompActiveAndNegated, nvars);

#ifndef NDEBUG
      /* and-constraints have to be merged in order to check for aggregation */
      for( v = 1; v < nvars; ++v )
      {
         SCIP_VAR* var1;
         SCIP_VAR* var2;

         /* it appears that some fixed variables were not yet deleted */
         if( SCIPvarGetLbGlobal(repvars[v-1]) > 0.5 || SCIPvarGetUbGlobal(repvars[v-1]) < 0.5 )
            goto TERMINATE;

         /* it appears that some fixed variables were not yet deleted */
         if( SCIPvarGetLbGlobal(repvars[v]) > 0.5 || SCIPvarGetUbGlobal(repvars[v]) < 0.5 )
            goto TERMINATE;

         assert(SCIPvarIsActive(repvars[v]) || (SCIPvarIsNegated(repvars[v]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v]))));
         assert(SCIPvarIsActive(repvars[v-1]) || (SCIPvarIsNegated(repvars[v-1]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v-1]))));
         assert(SCIPvarIsActive(repvars[v]) != negated[v]);
         assert(SCIPvarIsActive(repvars[v-1]) != negated[v-1]);

         var1 = (negated[v-1] ? SCIPvarGetNegationVar(repvars[v-1]) : repvars[v-1]);
         var2 = (negated[v] ? SCIPvarGetNegationVar(repvars[v]) : repvars[v]);
         assert(var1 != var2);
      }
#endif

      /* update the statuses of all appearing variables */
      for( v = nvars - 1; v >= 0; --v )
      {
         /* it appears that some fixed variables were not yet deleted */
         if( SCIPvarGetLbGlobal(repvars[v]) > 0.5 || SCIPvarGetUbGlobal(repvars[v]) < 0.5 )
            goto TERMINATE;

         assert(SCIPvarIsActive(repvars[v]) || (SCIPvarIsNegated(repvars[v]) && SCIPvarIsActive(SCIPvarGetNegationVar(repvars[v]))));
         assert(SCIPvarIsActive(repvars[v]) != negated[v]);

         /* we can only find an aggregation if all and constraints have the same variables */
         if( SCIPsortedvecFindPtr((void**)allvars, SCIPvarCompActiveAndNegated, repvars[v], nvars, &pos) )
         {
            assert(pos >= 0 && pos < nvars);

            ++(varcount[negated[v]][pos]);
         }
         else
            goto TERMINATE;
      }
   }

   zerocount = 0;
   onecount = 0;
   twocount = 0;
   othercount = 0;

   /* count number of multiple appearances of a variable */
   for( i = 1; i >= 0; --i )
   {
      for( v = nvars - 1; v >= 0; --v )
      {
         assert(SCIPvarIsActive(allvars[v]));

         if( varcount[i][v] == 0 )
            ++zerocount;
         else if( varcount[i][v] == 1 )
            ++onecount;
         else if( varcount[i][v] == 2 )
            ++twocount;
         else
            ++othercount;
      }
   }

   /* exactly one variable in all and-constraints appears as active and as negated variable */
   if( othercount == 0 )
   {
      /* we have a constraint in the form of: x1 + x2 * x3 * ... * x_n + ~x2 * x3 * ... * x_n == 1
       * this leads to the aggregation x1 = 1 - x3 * ... * x_n
       */
      if( nconsanddatas == 2 && twocount == nvars - 1 && onecount == 2 && zerocount == 1 )
      {
         SCIP_VAR** consvars;
         SCIP_Real* conscoefs;
         int nconsvars;
         SCIP_VAR* linvar;
         SCIP_Real lincoef;
         int nlinvars;

         /* allocate temporary memory */
         SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nlinvars + nconsanddatas) );
         SCIP_CALL( SCIPallocBufferArray(scip, &conscoefs, consdata->nlinvars + nconsanddatas) );

         /* get variables and coefficients */
         SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, consvars, conscoefs, &nconsvars) );
         assert(nconsvars == consdata->nlinvars + nconsanddatas);
         assert(conscoefs != NULL);

#ifndef NDEBUG
         /* all coefficients have to be 1 */
         for( v = 0; v < nconsvars; ++v )
            assert(SCIPisEQ(scip, conscoefs[v], 1.0));
#endif
         linvar = NULL;

         /* calculate all not artificial linear variables */
         SCIP_CALL( getLinVarsAndAndRess(scip, cons, consvars, conscoefs, nconsvars, &linvar, &lincoef, &nlinvars,
               NULL, NULL, NULL, NULL) );
         assert(nlinvars == 1);
         assert(linvar != NULL);

         SCIPfreeBufferArray(scip, &conscoefs);
         SCIPfreeBufferArray(scip, &consvars);

         /* if all and-constraints have exactly two variables */
         if( nvars == 2 )
         {
            SCIP_VAR* var;
            SCIP_Bool breaked;
            SCIP_Bool redundant;
            SCIP_Bool infeasible;
            SCIP_Bool aggregated;

            var = NULL;
            breaked = FALSE;

            /* find necessary variables, which only occur once */
            for( i = 1; i >= 0; --i )
            {
               for( v = nvars - 1; v >= 0; --v )
               {
                  assert(i == 1 || SCIPvarGetNegatedVar(allvars[v]) != NULL);
                  if( varcount[i][v] == 2 )
                  {
                     var = i ? SCIPvarGetNegatedVar(allvars[v]) : allvars[v];

                     breaked = TRUE;
                     break;
                  }
               }

               if( breaked )
                  break;
            }
            assert(var != NULL);

            SCIPdebugMsg(scip, "aggregating variables <%s> == 1 - <%s> in pseudoboolean <%s>\n", SCIPvarGetName(linvar), SCIPvarGetName(var), SCIPconsGetName(cons));

            SCIP_CALL( SCIPaggregateVars(scip, linvar, var, 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );

            SCIPdebugPrintCons(scip, cons, NULL);
            SCIPdebugMsg(scip, "aggregation of variables: <%s> == 1 - <%s>, infeasible = %u, aggregated = %u\n", SCIPvarGetName(linvar), SCIPvarGetName(var), infeasible, aggregated);

            if( infeasible )
               *cutoff = TRUE;
            else
            {
               if( aggregated )
                  ++(*naggrvars);

               /* delete old constraints */
               SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
               SCIP_CALL( SCIPdelCons(scip, cons) );
               (*ndelconss) += 2;
            }
         }
         /* @todo: otherwise delete in this constraint allvars[samepos] from all terms and delete all but one of them
          *
          * it is the same like aggregating linvar with the resultant of the product, which is the same in all and-
          * constraints without allvars[samepos]
          *
          * e.g. x1 + x2*x_3*...x_n + ~x2*x_3*...x_n = 1 => x1 = 1 - x_3*...x_n
          */
      } /*lint !e438*/
      /* we have a constraint in the form of: x1 + x2 * x3 + ~x2 * x3 + ~x2 * ~x3 == 1
       * this leads to the aggregation x1 = x2 * ~x3
       *
       * @todo: implement more general step, that one combination of the variables in the and constraints is missing in
       *        the pseudoboolean constraint, which leads to the same result, that the only linear variable is the
       *        resultant of the missing and-constraint
       */
      else if( nvars == 2 && nconsanddatas == 3 && twocount == 2 && onecount == 2 && zerocount == 0)
      {
         SCIP_VAR** consvars;
         SCIP_Real* conscoefs;
         int nconsvars;
         SCIP_VAR* linvar;
         SCIP_Real lincoef;
         int nlinvars;
         SCIP_VAR* newandvars[2];
         SCIP_Bool breaked;
         SCIP_CONS* newcons;
         char name[SCIP_MAXSTRLEN];

         /* allocate temporary memory */
         SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nlinvars + nconsanddatas) );
         SCIP_CALL( SCIPallocBufferArray(scip, &conscoefs, consdata->nlinvars + nconsanddatas) );

         /* get variables and coefficients */
         SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, consvars, conscoefs, &nconsvars) );
         assert(nconsvars == consdata->nlinvars + nconsanddatas);
         assert(conscoefs != NULL);

#ifndef NDEBUG
         /* all coefficients have to be 1 */
         for( v = 0; v < nconsvars; ++v )
            assert(SCIPisEQ(scip, conscoefs[v], 1.0));
#endif
         linvar = NULL;

         /* calculate all not artificial linear variables */
         SCIP_CALL( getLinVarsAndAndRess(scip, cons, consvars, conscoefs, nconsvars, &linvar, &lincoef, &nlinvars,
               NULL, NULL, NULL, NULL) );
         assert(nlinvars == 1);
         assert(linvar != NULL);

         SCIPfreeBufferArray(scip, &conscoefs);
         SCIPfreeBufferArray(scip, &consvars);

         newandvars[0] = NULL;
         newandvars[1] = NULL;
         breaked = FALSE;

         /* find necessary variables, which only occur once */
         for( i = 1; i >= 0; --i )
         {
            for( v = nvars - 1; v >= 0; --v )
            {
               assert(i == 1 || SCIPvarGetNegatedVar(allvars[v]) != NULL);
               if( varcount[i][v] == 1 )
               {
                  if( newandvars[0] == NULL )
                     newandvars[0] = i ? SCIPvarGetNegatedVar(allvars[v]) : allvars[v];
                  else
                  {
                     assert(newandvars[1] == NULL);
                     newandvars[1] = i ? SCIPvarGetNegatedVar(allvars[v]) : allvars[v];

                     breaked = TRUE;
                     break;
                  }
               }
            }

            if( breaked )
               break;
         }
         assert(newandvars[0] != NULL && newandvars[1] != NULL);

         (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "andcons_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(linvar));
         SCIP_CALL( SCIPcreateConsAnd(scip, &newcons, name, linvar, nvars, newandvars,
               TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
         SCIP_CALL( SCIPaddCons(scip, newcons) );
         SCIPdebugPrintCons(scip, newcons, NULL);
         SCIP_CALL( SCIPreleaseCons(scip, &newcons) );

         /* delete old constraints */
         SCIP_CALL( SCIPdelCons(scip, consdata->lincons) );
         SCIP_CALL( SCIPdelCons(scip, cons) );
         (*ndelconss) += 2;
      } /*lint !e438*/
   }

   if( SCIPconsIsDeleted(cons) )
   {
      /* update the uses counter of consandata objects which are used in pseudoboolean constraint, which was deleted and
       * probably delete and-constraints
       */
      SCIP_CALL( updateConsanddataUses(scip, cons, conshdlrdata, ndelconss) );
   }

 TERMINATE:
   /* free temporary memory */
   SCIPfreeBufferArray(scip, &negated);
   SCIPfreeBufferArray(scip, &repvars);
   SCIPfreeBufferArray(scip, &(varcount[1]));
   SCIPfreeBufferArray(scip, &(varcount[0]));
   SCIPfreeBufferArray(scip, &allvars);

   return SCIP_OKAY;
}

/** adds symmetry information of constraint to a symmetry detection graph */
static
SCIP_RETCODE addSymmetryInformation(
   SCIP*                 scip,               /**< SCIP pointer */
   SYM_SYMTYPE           symtype,            /**< type of symmetries that need to be added */
   SCIP_CONS*            cons,               /**< constraint */
   SYM_GRAPH*            graph,              /**< symmetry detection graph */
   SCIP_Bool*            success             /**< pointer to store whether symmetry information could be added */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_VAR** tmpvars = NULL;
   SCIP_VAR** vars;
   SCIP_CONS* lincons;
   SCIP_LINEARCONSTYPE constype;
   SCIP_Real* tmpvals = NULL;
   SCIP_Real* vals;
   SCIP_Real constant = 0.0;
   SCIP_Real lhs;
   SCIP_Real rhs;
   int tmpnvars;
   int rootnodeidx;
   int nodeidx;
   int nvars;
   int i;
   int c;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(graph != NULL);
   assert(success != NULL);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   /* allocate buffer to hold variables for creating of symmetry detection graph */
   nvars = SCIPgetNVars(scip);
   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );

   /* add root node to symmetry detection graph */
   lhs = SCIPgetLhsPseudoboolean(scip, cons);
   rhs = SCIPgetRhsPseudoboolean(scip, cons);
   SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, lhs, rhs, &rootnodeidx) );

   /* possibly add node and edge encoding whether constraint is soft */
   vars[0] = SCIPgetIndVarPseudoboolean(scip, cons);
   if( vars[0] != NULL )
   {
      vals[0] = 1.0;
      tmpnvars = 1;
      constant = 0.0;

      SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int)SYM_CONSOPTYPE_PB_SOFT, &nodeidx) );
      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rootnodeidx, nodeidx, TRUE, consdata->weight) );
      SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &tmpnvars, &constant,
            SCIPisTransformed(scip)) );
      SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, tmpnvars, constant) );
   }

   /* add nodes and edges encoding linear part of the pseudoboolean cons */
   lincons = SCIPgetLinearConsPseudoboolean(scip, cons);
   constype = SCIPgetLinearConsTypePseudoboolean(scip, cons);

   /* collect information about linear constraint */
   tmpnvars = 0;
   switch( constype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      tmpvars = SCIPgetVarsLinear(scip, lincons);
      tmpnvars = SCIPgetNVarsLinear(scip, lincons);
      tmpvals = SCIPgetValsLinear(scip, lincons);
      for( i = 0; i < tmpnvars; ++i )
         vals[i] = tmpvals[i];
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
      tmpvars = SCIPgetVarsLogicor(scip, lincons);
      tmpnvars = SCIPgetNVarsLogicor(scip, lincons);
      for( i = 0; i < tmpnvars; ++i )
         vals[i] = 1.0;
      break;
   case SCIP_LINEARCONSTYPE_KNAPSACK:
      tmpvars = SCIPgetVarsKnapsack(scip, lincons);
      tmpnvars = SCIPgetNVarsKnapsack(scip, lincons);
      for( i = 0; i < tmpnvars; ++i )
         vals[i] = (SCIP_Real)SCIPgetWeightsKnapsack(scip, cons)[i];
      break;
   case SCIP_LINEARCONSTYPE_SETPPC:
      tmpvars = SCIPgetVarsSetppc(scip, lincons);
      tmpnvars = SCIPgetNVarsSetppc(scip, lincons);
      for( i = 0; i < tmpnvars; ++i )
         vals[i] = 1.0;
      break;
   default:
      SCIPfreeBufferArray(scip, &vals);
      SCIPfreeBufferArray(scip, &vars);
      *success = FALSE;

      return SCIP_OKAY;
   } /*lint !e788*/
   assert(tmpvars != NULL);
   for( i = 0; i < tmpnvars; ++i )
      vars[i] = tmpvars[i];
   constant = 0.0;

   /* create nodes and edges for linear part */
   SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int)SYM_CONSOPTYPE_PB_LINEAR, &nodeidx) );
   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rootnodeidx, nodeidx, FALSE, 0.0) );

   SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &tmpnvars, &constant,
         SCIPisTransformed(scip)) );
   SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, tmpnvars, constant) );

   /* create nodes and edges for AND constraints */
   for( c = 0; c < consdata->nconsanddatas; ++c )
   {
      assert(consdata->consanddatas[c] != NULL);

      SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int)SYM_CONSOPTYPE_PB_AND, &nodeidx) );
      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rootnodeidx, nodeidx, TRUE, consdata->andcoefs[c]) );

      tmpnvars = consdata->consanddatas[c]->nvars;
      for( i = 0; i < tmpnvars; ++i )
         vars[i] = consdata->consanddatas[c]->vars[i];
      for( i = 0; i < tmpnvars; ++i )
         vals[i] = 1.0;
      constant = 0.0;

      SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &tmpnvars, &constant,
            SCIPisTransformed(scip)) );
      SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, tmpnvars, constant) );
   }

   SCIPfreeBufferArray(scip, &vals);
   SCIPfreeBufferArray(scip, &vars);

   *success = TRUE;

   return SCIP_OKAY;
}


/*
 * Callback methods of constraint handler
 */

#ifdef NONLINCONSUPGD_PRIORITY
#include "scip/cons_nonlinear.h"
/** tries to upgrade a nonlinear constraint into a pseudoboolean constraint */
static
SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdPseudoboolean)
{
   SCIP_EXPRGRAPH* exprgraph;
   SCIP_EXPRGRAPHNODE* node;
   SCIP_Real lhs;
   SCIP_Real rhs;
   SCIP_VAR* var;
   SCIP_VAR* objvar = NULL;
   SCIP_VAR** linvars = NULL;
   int nlinvars;
   SCIP_VAR*** terms;
   int nterms;
   int* ntermvars;
   SCIP_Real* termvals;
   int i;
   int j;

   assert(nupgdconss != NULL);
   assert(upgdconss != NULL);

   *nupgdconss = 0;

   node = SCIPgetExprgraphNodeNonlinear(scip, cons);

   /* no interest in linear constraints */
   if( node == NULL )
      return SCIP_OKAY;

   switch( SCIPexprgraphGetNodeOperator(node) )
   {
   case SCIP_EXPR_VARIDX:
   case SCIP_EXPR_CONST:
   case SCIP_EXPR_PLUS:
   case SCIP_EXPR_MINUS:
   case SCIP_EXPR_SUM:
   case SCIP_EXPR_LINEAR:
      /* these should not appear as exprgraphnodes after constraint presolving */
      return SCIP_OKAY;

   case SCIP_EXPR_MUL:
   case SCIP_EXPR_DIV:
   case SCIP_EXPR_SQUARE:
   case SCIP_EXPR_SQRT:
   case SCIP_EXPR_REALPOWER:
   case SCIP_EXPR_INTPOWER:
   case SCIP_EXPR_SIGNPOWER:
   case SCIP_EXPR_EXP:
   case SCIP_EXPR_LOG:
   case SCIP_EXPR_SIN:
   case SCIP_EXPR_COS:
   case SCIP_EXPR_TAN:
      /* case SCIP_EXPR_ERF: */
      /* case SCIP_EXPR_ERFI: */
   case SCIP_EXPR_MIN:
   case SCIP_EXPR_MAX:
   case SCIP_EXPR_ABS:
   case SCIP_EXPR_SIGN:
   case SCIP_EXPR_PRODUCT:
   case SCIP_EXPR_USER:
      /* these do not look like a proper pseudoboolean expression (assuming the expression graph simplifier did run) */
      return SCIP_OKAY;

   case SCIP_EXPR_QUADRATIC:  /* let cons_quadratic still handle these for now */
      return SCIP_OKAY;

   case SCIP_EXPR_POLYNOMIAL:
      /* these mean that we have something polynomial */
      break;

   case SCIP_EXPR_PARAM:
   case SCIP_EXPR_LAST:
   default:
      SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
      return SCIP_OKAY;
   }

   lhs = SCIPgetLhsNonlinear(scip, cons);
   rhs = SCIPgetRhsNonlinear(scip, cons);

   /* we need all linear variables to be binary */
   for( i = 0; i < SCIPgetNLinearVarsNonlinear(scip, cons); ++i )
   {
      var = SCIPgetLinearVarsNonlinear(scip, cons)[i];
      assert(var != NULL);

      if( SCIPvarIsBinary(var) )
         continue;

      SCIPdebugMsg(scip, "not pseudoboolean because linear variable <%s> is not binary\n", SCIPvarGetName(var));
      return SCIP_OKAY;
   }

   /* if simplified, then all children of root node should be variables, we need all of them to be binary */
   exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
   for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
   {
      SCIP_EXPRGRAPHNODE* child;

      child = SCIPexprgraphGetNodeChildren(node)[i];
      assert(child != NULL);
      if( SCIPexprgraphGetNodeOperator(child) != SCIP_EXPR_VARIDX )
      {
         SCIPdebugMsg(scip, "not pseudoboolean because child %d is not a variable\n", i);
         return SCIP_OKAY;
      }

      var = (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, child);
      assert(var != NULL);
      if( !SCIPvarIsBinary(var) )
      {
         SCIPdebugMsg(scip, "not pseudoboolean because nonlinear var <%s> is not binary\n", SCIPvarGetName(var));
         return SCIP_OKAY;
      }
   }

   /* setup a pseudoboolean constraint */

   if( upgdconsssize < 1 )
   {
      /* request larger upgdconss array */
      *nupgdconss = -1;
      return SCIP_OKAY;
   }

   SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> to pseudo-boolean\n", SCIPconsGetName(cons));

   if( !SCIPisInfinity(scip, -lhs) )
      lhs -= SCIPexprgraphGetNodePolynomialConstant(node);
   if( !SCIPisInfinity(scip, -rhs) )
      rhs -= SCIPexprgraphGetNodePolynomialConstant(node);

   /* setup linear part, if not identical */
   if( objvar != NULL )
   {
      SCIP_CALL( SCIPallocBufferArray(scip, &linvars, SCIPgetNLinearVarsNonlinear(scip, cons)-1) );
      nlinvars = 0;
      for( i = 0; i < SCIPgetNLinearVarsNonlinear(scip, cons); ++i )
      {
         var = SCIPgetLinearVarsNonlinear(scip, cons)[i];
         if( var != objvar )
            linvars[nlinvars++] = var;
      }
   }
   else
      nlinvars = SCIPgetNLinearVarsNonlinear(scip, cons);

   /* setup nonlinear terms */
   nterms = SCIPexprgraphGetNodePolynomialNMonomials(node);
   SCIP_CALL( SCIPallocBufferArray(scip, &terms, nterms) );
   SCIP_CALL( SCIPallocBufferArray(scip, &ntermvars, nterms) );
   SCIP_CALL( SCIPallocBufferArray(scip, &termvals, nterms) );

   for( i = 0; i < nterms; ++i )
   {
      SCIP_EXPRDATA_MONOMIAL* monomial;

      monomial = SCIPexprgraphGetNodePolynomialMonomials(node)[i];
      assert(monomial != NULL);

      ntermvars[i] = SCIPexprGetMonomialNFactors(monomial);
      SCIP_CALL( SCIPallocBufferArray(scip, &terms[i], ntermvars[i]) );

      for( j = 0; j < SCIPexprGetMonomialNFactors(monomial); ++j )
      {
         terms[i][j] = (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[SCIPexprGetMonomialChildIndices(monomial)[j]]);
         assert(SCIPexprGetMonomialExponents(monomial)[j] > 0.0);
      }

      termvals[i] = SCIPexprGetMonomialCoef(monomial);
   }

   *nupgdconss = 1;
   SCIP_CALL( SCIPcreateConsPseudoboolean(scip, &upgdconss[0], SCIPconsGetName(cons),
         objvar != NULL ? linvars : SCIPgetLinearVarsNonlinear(scip, cons), nlinvars, SCIPgetLinearCoefsNonlinear(scip, cons),
         terms, nterms, ntermvars, termvals, NULL, 0.0, FALSE, objvar,
         lhs, rhs,
         SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
         SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
         SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

   for( i = nterms-1; i >= 0; --i )
      SCIPfreeBufferArray(scip, &terms[i]);

   SCIPfreeBufferArray(scip, &terms);
   SCIPfreeBufferArray(scip, &ntermvars);
   SCIPfreeBufferArray(scip, &termvals);
   SCIPfreeBufferArrayNull(scip, &linvars);

   return SCIP_OKAY;
}
#endif

/** copy method for constraint handler plugins (called when SCIP copies plugins) */
static
SCIP_DECL_CONSHDLRCOPY(conshdlrCopyPseudoboolean)
{  /*lint --e{715}*/
   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);

   /* call inclusion method of constraint handler */
   SCIP_CALL( SCIPincludeConshdlrPseudoboolean(scip) );

   *valid = TRUE;

   return SCIP_OKAY;
}

/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
static
SCIP_DECL_CONSFREE(consFreePseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSHDLRDATA* conshdlrdata;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);

   /* free constraint handler data */
   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   SCIP_CALL( conshdlrdataFree(scip, &conshdlrdata) );

   SCIPconshdlrSetData(conshdlr, NULL);

   return SCIP_OKAY;
}


/** initialization method of constraint handler (called after problem was transformed) */
static
SCIP_DECL_CONSINIT(consInitPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSHDLRDATA* conshdlrdata;
   int c;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);

   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   /* check each constraint and get transformed constraints */
   for( c = conshdlrdata->nallconsanddatas - 1; c >= 0; --c )
   {
      SCIP_CONS* andcons;
      SCIP_VAR* resultant;
#ifndef NDEBUG
      SCIP_VAR** vars;
      int nvars;
      int v;

      assert(conshdlrdata->allconsanddatas[c] != NULL);
      assert(conshdlrdata->allconsanddatas[c]->newvars == NULL);

      vars = conshdlrdata->allconsanddatas[c]->vars;
      nvars = conshdlrdata->allconsanddatas[c]->nvars;
      assert(vars != NULL || nvars == 0);

      /* check for correct variables data */
      for( v = nvars - 1; v > 0; --v )
      {
         assert(SCIPvarIsTransformed(vars[v])); /*lint !e613*/
         assert(SCIPvarGetIndex(vars[v]) >= SCIPvarGetIndex(vars[v-1])); /*lint !e613*/
      }
      assert(nvars == 0 || SCIPvarIsTransformed(vars[0])); /*lint !e613*/
#endif

      andcons = conshdlrdata->allconsanddatas[c]->cons;
      assert(andcons != NULL);

      assert(SCIPconsIsTransformed(andcons));

      resultant = SCIPgetResultantAnd(scip, andcons);
      /* insert new mapping */
      assert(!SCIPhashmapExists(conshdlrdata->hashmap, (void*)resultant));
      SCIP_CALL( SCIPhashmapInsert(conshdlrdata->hashmap, (void*)resultant, (void*)(conshdlrdata->allconsanddatas[c])) );

      SCIPdebugMsg(scip, "insert into hashmap <%s> (%p) -> <%s> (%p/%p)\n", SCIPvarGetName(resultant), (void*)resultant,
         SCIPconsGetName(conshdlrdata->allconsanddatas[c]->cons), (void*)(conshdlrdata->allconsanddatas[c]),
         (void*)(conshdlrdata->allconsanddatas[c]->cons));
   }

   return SCIP_OKAY;
}

/** presolving initialization method of constraint handler (called when presolving is about to begin) */
static
SCIP_DECL_CONSINITPRE(consInitprePseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSHDLRDATA* conshdlrdata;
   int c;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);

   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   /* decompose all pseudo boolean constraints into a "linear" constraint and "and" constraints */
   for( c = 0; c < nconss; ++c )
   {
      SCIP_CONS* cons;
      SCIP_CONSDATA* consdata;
      SCIP_VAR** vars;
      SCIP_Real* coefs;
      int nvars;

      cons = conss[c];
      assert(cons != NULL);

      /* only added constraints can be upgraded */
      if( !SCIPconsIsAdded(cons) )
         continue;

      consdata = SCIPconsGetData(cons);
      assert(consdata != NULL);

      /* only keep hard constraints if desired */
      if( !conshdlrdata->decomposenormalpbcons && !consdata->issoftcons )
         continue;

      /* gets number of variables in linear constraint */
      SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );

      /* allocate temporary memory */
      SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );

      /* get variables and coefficient of linear constraint */
      SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
      assert(coefs != NULL || nvars == 0);

      /* hard constraint */
      if( !consdata->issoftcons )
      {
         /* @todo: maybe better create a new linear constraint and let scip do the upgrade */

         /* mark linear constraint not to be upgraded - otherwise we loose control over it */
         SCIPconsAddUpgradeLocks(consdata->lincons, +1);

         /* update and constraint flags */
         SCIP_CALL( updateAndConss(scip, cons) );
      }
      /* soft constraint */
      else
      {
         SCIP_VAR* negindvar;
         char name[SCIP_MAXSTRLEN];
         SCIP_Real lhs;
         SCIP_Real rhs;
         SCIP_Bool initial;
         SCIP_Bool updateandconss;
         int v;

         assert(consdata->weight != 0);
         assert(consdata->indvar != NULL);

         /* get negation of indicator variable */
         SCIP_CALL( SCIPgetNegatedVar(scip, consdata->indvar, &negindvar) );
         assert(negindvar != NULL);

         /* get sides of linear constraint */
         SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &lhs, &rhs) );
         assert(!SCIPisInfinity(scip, lhs));
         assert(!SCIPisInfinity(scip, -rhs));
         assert(SCIPisLE(scip, lhs, rhs));

         /* @todo: split up sides into separate soft constraints in advance */
         /* assert(SCIPisInfinity(scip, -lhs) || SCIPisInfinity(scip, rhs)); */

         updateandconss = FALSE;

         /* with indicator */
         if( conshdlrdata->decomposeindicatorpbcons )
         {
            SCIP_CONS* indcons;

            /* @todo check whether it's better to set the initial flag to false */
            initial = SCIPconsIsInitial(cons); /* FALSE; */

            if( !SCIPisInfinity(scip, rhs) )
            {
               /* first we are modelling the implication that if the negation of the indicator variable is on, the constraint
                * is enabled */
               /* indvar == 0 => a^T*x <= rhs */

               (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_rhs_ind", SCIPconsGetName(cons));

               SCIP_CALL( SCIPcreateConsIndicator(scip, &indcons, name, negindvar, nvars, vars, coefs, rhs,
                     initial, SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
                     SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               /* update and constraint flags */
               SCIP_CALL( updateAndConss(scip, cons) );
               updateandconss = TRUE;

               SCIP_CALL( SCIPaddCons(scip, indcons) );
               SCIPdebugPrintCons(scip, indcons, NULL);
               SCIP_CALL( SCIPreleaseCons(scip, &indcons) );
            }

            if( !SCIPisInfinity(scip, -lhs) )
            {
               /* second we are modelling the implication that if the negation of the indicator variable is on, the constraint
                * is enabled */
               /* change the a^T*x >= lhs to -a^Tx<= -lhs, for indicator constraint */

               for( v = nvars - 1; v >= 0; --v )
                  coefs[v] *= -1;

               (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lhs_ind", SCIPconsGetName(cons));

               SCIP_CALL( SCIPcreateConsIndicator(scip, &indcons, name, negindvar, nvars, vars, coefs, -lhs,
                     initial, SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
                     SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               if( !updateandconss )
               {
                  /* update and constraint flags */
                  SCIP_CALL( updateAndConss(scip, cons) );
               }

               SCIP_CALL( SCIPaddCons(scip, indcons) );
               SCIPdebugPrintCons(scip, indcons, NULL);
               SCIP_CALL( SCIPreleaseCons(scip, &indcons) );
            }
         }
         /* with linear */
         else
         {
            SCIP_CONS* lincons;
            SCIP_Real maxact;
            SCIP_Real minact;
            SCIP_Real lb;
            SCIP_Real ub;

            maxact = 0.0;
            minact = 0.0;

            /* adding all linear coefficients up */
            for( v = nvars - 1; v >= 0; --v )
               if( coefs[v] > 0 )
                  maxact += coefs[v];
               else
                  minact += coefs[v];

            if( SCIPisInfinity(scip, maxact) )
            {
               SCIPwarningMessage(scip, "maxactivity = %g exceed infinity value.\n", maxact);
            }
            if( SCIPisInfinity(scip, -minact) )
            {
               SCIPwarningMessage(scip, "minactivity = %g exceed -infinity value.\n", minact);
            }

            /* @todo check whether it's better to set the initial flag to false */
            initial = SCIPconsIsInitial(cons); /* FALSE; */

            /* first soft constraints for lhs */
            if( !SCIPisInfinity(scip, -lhs) )
            {
               /* first we are modelling the feasibility of the soft constraint by adding a slack variable */
               /* we ensure that if indvar == 1 => (a^T*x + ub*indvar >= lhs) */
               ub = lhs - minact;

               (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lhs_part1", SCIPconsGetName(cons));

               SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars, vars, coefs, lhs, SCIPinfinity(scip),
                     initial, SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
                     SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               /* update and constraint flags */
               SCIP_CALL( updateAndConss(scip, cons) );
               updateandconss = TRUE;

               /* add artificial indicator variable */
               SCIP_CALL( SCIPaddCoefLinear(scip, lincons, consdata->indvar, ub) );

               SCIP_CALL( SCIPaddCons(scip, lincons) );
               SCIPdebugPrintCons(scip, lincons, NULL);
               SCIP_CALL( SCIPreleaseCons(scip, &lincons) );

               /* second we are modelling the implication that if the slack variable is on( negation is off), the constraint
                * is disabled, so only the cost arise if the slack variable is necessary */
               /* indvar == 1 => (a^T*x (+ ub * negindvar) <= lhs - 1) */
               ub = lhs - maxact - 1;

               (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lhs_part2", SCIPconsGetName(cons));

               SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars, vars, coefs, -SCIPinfinity(scip), lhs - 1,
                     initial, SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
                     SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               /* add artificial indicator variable */
               SCIP_CALL( SCIPaddCoefLinear(scip, lincons, negindvar, ub) );

               SCIP_CALL( SCIPaddCons(scip, lincons) );
               SCIPdebugPrintCons(scip, lincons, NULL);
               SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
            }

            /* second soft constraints for rhs */
            if( !SCIPisInfinity(scip, rhs) )
            {
               /* first we are modelling the feasibility of the soft-constraint by adding a slack variable */
               /* indvar == 1 => (a^T*x + lb * indvar <= rhs) */
               lb = rhs - maxact;

               (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_rhs_part1", SCIPconsGetName(cons));

               SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars, vars, coefs, -SCIPinfinity(scip), rhs,
                     initial, SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
                     SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               if( !updateandconss )
               {
                  /* update and constraint flags */
                  SCIP_CALL( updateAndConss(scip, cons) );
               }

               /* add artificial indicator variable */
               SCIP_CALL( SCIPaddCoefLinear(scip, lincons, consdata->indvar, lb) );

               SCIP_CALL( SCIPaddCons(scip, lincons) );
               SCIPdebugPrintCons(scip, lincons, NULL);
               SCIP_CALL( SCIPreleaseCons(scip, &lincons) );

               /* second we are modelling the implication that if the slack variable is on( negation is off), the constraint
                * is disabled, so only the cost arise if the slack variable is necessary */
               /* indvar == 1 => (a^T*x (+ lb * negindvar) >= rhs + 1) */
               lb = rhs - minact + 1;

               (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_rhs_part2", SCIPconsGetName(cons));

               SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, nvars, vars, coefs, rhs + 1, SCIPinfinity(scip),
                     initial, SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
                     SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
                     SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );

               /* add artificial indicator variable */
               SCIP_CALL( SCIPaddCoefLinear(scip, lincons, negindvar, lb) );

               SCIP_CALL( SCIPaddCons(scip, lincons) );
               SCIPdebugPrintCons(scip, lincons, NULL);
               SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
            }
         }

         /* release corresponding unadded linear constraint, other constraints were added */
         assert(!SCIPconsIsAdded(consdata->lincons));
         SCIP_CALL( SCIPreleaseCons(scip, &consdata->lincons) );
      }

      /* free temporary memory */
      SCIPfreeBufferArray(scip, &coefs);
      SCIPfreeBufferArray(scip, &vars);

      /* @todo: maintain soft inequality constraint if not decomposeindicatorpbcons */
      /* remove pseudo boolean constraint, and-constraints are still active */
      SCIP_CALL( SCIPdelCons(scip, cons) );
   }

   return SCIP_OKAY;
}

/** frees specific constraint data */
static
SCIP_DECL_CONSDELETE(consDeletePseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_Bool isorig;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(cons != NULL);
   assert(consdata != NULL);
   assert(*consdata != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);

   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   isorig = SCIPconsIsOriginal(cons);

   /* count number of used consanddata objects in original problem */
   if( isorig )
   {
#ifndef NDEBUG
      int c;
      assert((*consdata)->lincons == NULL || SCIPconsIsOriginal((*consdata)->lincons));

      for( c = (*consdata)->nconsanddatas - 1; c >= 0; --c )
      {
         assert((*consdata)->consanddatas[c]->nuses == 0);
         assert((*consdata)->consanddatas[c]->cons == NULL);
         assert((*consdata)->consanddatas[c]->noriguses == 0 || ((*consdata)->consanddatas[c]->origcons != NULL && SCIPconsIsOriginal((*consdata)->consanddatas[c]->origcons)));
      }
#endif
      conshdlrdata->noriguses -= (*consdata)->nconsanddatas;
   }
   assert(conshdlrdata->noriguses >= 0);

   /* free pseudo boolean constraint */
   SCIP_CALL( consdataFree(scip, consdata, isorig, conshdlrdata) );

   return SCIP_OKAY;
}

/** transforms constraint data into data belonging to the transformed problem */
static
SCIP_DECL_CONSTRANS(consTransPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSDATA* sourcedata;
   SCIP_CONSDATA* targetdata;
   SCIP_CONS** andconss;
   int c;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
   assert(sourcecons != NULL);
   assert(targetcons != NULL);
   sourcedata = SCIPconsGetData(sourcecons);
   assert(sourcedata != NULL);
   assert(sourcedata->consanddatas != NULL || sourcedata->nconsanddatas == 0);

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &andconss, sourcedata->nconsanddatas) );

   /* copy and-constraints */
   for( c = sourcedata->nconsanddatas - 1; c >= 0; --c )
   {
      assert(sourcedata->consanddatas[c] != NULL);
      andconss[c] = sourcedata->consanddatas[c]->origcons;
      assert(andconss[c] != NULL);
      assert(SCIPconsIsOriginal(andconss[c]));
   }

   /* create pseudoboolean constraint data for target constraint */
   SCIP_CALL( consdataCreate(scip, conshdlr, &targetdata, sourcedata->lincons, sourcedata->linconstype, andconss,
         sourcedata->andcoefs, sourcedata->andnegs, sourcedata->nconsanddatas, sourcedata->indvar, sourcedata->weight,
         sourcedata->issoftcons, sourcedata->lhs, sourcedata->rhs, SCIPconsIsChecked(sourcecons), TRUE) );

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &andconss);

   /* create target constraint */
   SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
         SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
         SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
         SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
         SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );

   return SCIP_OKAY;
}

/** constraint enforcing method of constraint handler for LP solutions */
static
SCIP_DECL_CONSENFOLP(consEnfolpPseudoboolean)
{  /*lint --e{715}*/
   SCIP_Bool violated;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(result != NULL);

   violated = FALSE;

   /* check all and-constraints */
   SCIP_CALL( checkAndConss(scip, conshdlr, NULL, &violated) );

   if( violated )
      *result = SCIP_INFEASIBLE;
   else
      *result = SCIP_FEASIBLE;

   return SCIP_OKAY;
}


/** constraint enforcing method of constraint handler for relaxation solutions */
static
SCIP_DECL_CONSENFORELAX(consEnforelaxPseudoboolean)
{  /*lint --e{715}*/
   SCIP_Bool violated;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(result != NULL);

   violated = FALSE;

   /* check all and-constraints */
   SCIP_CALL( checkAndConss(scip, conshdlr, sol, &violated) );

   if( violated )
      *result = SCIP_INFEASIBLE;
   else
      *result = SCIP_FEASIBLE;

   return SCIP_OKAY;
}


/** constraint enforcing method of constraint handler for pseudo solutions */
static
SCIP_DECL_CONSENFOPS(consEnfopsPseudoboolean)
{  /*lint --e{715}*/
   SCIP_Bool violated;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(result != NULL);

   violated = FALSE;

   /* check all and-constraints */
   SCIP_CALL( checkAndConss(scip, conshdlr, NULL, &violated) );

   if( violated )
      *result = SCIP_INFEASIBLE;
   else
      *result = SCIP_FEASIBLE;

   return SCIP_OKAY;
}


/** feasibility check method of constraint handler for integral solutions */
static
SCIP_DECL_CONSCHECK(consCheckPseudoboolean)
{  /*lint --e{715}*/
   SCIP_Bool violated;
   int c;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(sol != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(result != NULL);

   *result = SCIP_FEASIBLE;

   if( nconss > 0 )
   {
      if( SCIPconsIsOriginal(conss[0]) )
      {
         SCIP_CONSDATA* consdata;

         for( c = nconss - 1; c >= 0 && (*result == SCIP_FEASIBLE || completely); --c )
         {
            consdata = SCIPconsGetData(conss[c]);
            assert(consdata != NULL);

            if( consdata->issoftcons )
            {
               assert(consdata->indvar != NULL);

               if( SCIPisEQ(scip, SCIPgetSolVal(scip, sol, consdata->indvar), 1.0) )
                  continue;
            }

            SCIP_CALL( checkOrigPbCons(scip, conss[c], sol, &violated, printreason) );
            if( violated )
               *result = SCIP_INFEASIBLE;
         }
      }
      else
      {
         /* check all and-constraints */
         SCIP_CALL( checkAndConss(scip, conshdlr, sol, &violated) );
         if( violated )
            *result = SCIP_INFEASIBLE;
      }
   }

   return SCIP_OKAY;
}


/** presolving method of constraint handler */
static
SCIP_DECL_CONSPRESOL(consPresolPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_Bool cutoff;
   int firstchange;
   int firstupgradetry;
   int oldnfixedvars;
   int oldnaggrvars;
   int oldnchgbds;
   int oldndelconss;
   int oldnupgdconss;
   int oldnchgcoefs;
   int oldnchgsides;
   int c;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(result != NULL);

   /* remember old preprocessing counters */
   oldnfixedvars = *nfixedvars;
   oldnaggrvars = *naggrvars;
   oldnchgbds = *nchgbds;
   oldndelconss = *ndelconss;
   oldnupgdconss = *nupgdconss;
   oldnchgcoefs = *nchgcoefs;
   oldnchgsides = *nchgsides;

   /* get constraint handler data */
   conshdlrdata = SCIPconshdlrGetData(conshdlr);

   /* compute all changes in consanddata objects */
   SCIP_CALL( computeConsAndDataChanges(scip, conshdlrdata) );

   firstchange = INT_MAX;
   firstupgradetry = INT_MAX;
   cutoff = FALSE;

   for( c = 0; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
   {
      SCIP_CONS* cons;
      SCIP_CONSDATA* consdata;
      SCIP_VAR** vars;
      SCIP_Real* coefs;
      int nvars;
      SCIP_VAR** linvars;
      SCIP_Real* lincoefs;
      int nlinvars;
      SCIP_VAR** andress;
      SCIP_Real* andcoefs;
      SCIP_Bool* andnegs;
      int nandress;
      SCIP_Real newlhs;
      SCIP_Real newrhs;

      cons = conss[c];
      assert(cons != NULL);
      assert(SCIPconsIsActive(cons));

      consdata = SCIPconsGetData(cons);
      assert(consdata != NULL);
      assert(consdata->lincons != NULL);

      /* get sides of linear constraint */
      SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &newlhs, &newrhs) );
      assert(!SCIPisInfinity(scip, newlhs));
      assert(!SCIPisInfinity(scip, -newrhs));
      assert(SCIPisLE(scip, newlhs, newrhs));

      /* gets number of variables in linear constraint */
      SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );

      /* allocate temporary memory */
      SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &andress, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &andcoefs, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &andnegs, nvars) );

      /* get variables and coefficient of linear constraint */
      SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
      assert(coefs != NULL || nvars == 0);

      /* calculate all not artificial linear variables and all artificial and-resultants */
      SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars,
            andress, andcoefs, andnegs, &nandress) );

      /* update all locks inside this constraint and all captures on all and-constraints */
      SCIP_CALL( correctLocksAndCaptures(scip, cons, conshdlrdata, newlhs, newrhs, andress, andcoefs, andnegs, nandress) );

      /* if linear constraint is redundant, pseudoboolean constraint is redundant too */
      if( SCIPconsIsDeleted(consdata->lincons) )
      {
         /* update and-constraint flags */
         SCIP_CALL( updateAndConss(scip, cons) );

         SCIP_CALL( SCIPdelCons(scip, cons) );
         ++(*ndelconss);

         goto CONTTERMINATE;
      }

      /* we can only presolve pseudoboolean constraints, that are not modifiable */
      if( SCIPconsIsModifiable(cons) )
         goto CONTTERMINATE;

      SCIPdebugMsg(scip, "presolving pseudoboolean constraint <%s>\n", SCIPconsGetName(cons));
      SCIPdebugPrintCons(scip, cons, NULL);

      /* remember the first changed constraint to begin the next aggregation round with */
      if( firstchange == INT_MAX && consdata->changed )
         firstchange = c;

      if( consdata->changed && !SCIPisStopped(scip) )
      {
         /* check if we can aggregated some variables */
         SCIP_CALL( findAggregation(scip, cons, conshdlrdata, ndelconss, naggrvars, &cutoff) );
      }

      /* if aggregation also deleted the constraint we can go to the next */
      if( !SCIPconsIsActive(cons) )
         goto CONTTERMINATE;

      if( consdata->changed )
      {
         /* try upgrading pseudoboolean constraint to a linear constraint and/or remove possible and-constraints */
         SCIP_CALL( tryUpgrading(scip, cons, conshdlrdata, ndelconss, naddconss, nfixedvars, nchgcoefs, nchgsides, &cutoff) );
         if( cutoff )
            goto CONTTERMINATE;
      }

      /* if upgrading deleted the pseudoboolean constraint we go on */
      if( !SCIPconsIsActive(cons) )
         goto CONTTERMINATE;

      /* remember the first constraint that was not yet tried to be upgraded, to begin the next upgrading round with */
      if( firstupgradetry == INT_MAX && !consdata->upgradetried )
         firstupgradetry = c;

      while( !consdata->presolved && !SCIPisStopped(scip) )
      {
         /* mark constraint being presolved and propagated */
         consdata->presolved = TRUE;

         /* add cliques to the clique table */
         SCIP_CALL( addCliques(scip, cons, &cutoff, naggrvars, nchgbds) );
         if( cutoff )
            break;

         /* propagate constraint */
         SCIP_CALL( propagateCons(scip, cons, &cutoff, ndelconss) );
         if( cutoff )
            break;
      }

   CONTTERMINATE:

      /* reset changed flag */
      if( SCIPconsIsActive(cons) )
      {
         consdata->changed = FALSE;
      }

      /* free temporary memory */
      SCIPfreeBufferArray(scip, &andnegs);
      SCIPfreeBufferArray(scip, &andcoefs);
      SCIPfreeBufferArray(scip, &andress);
      SCIPfreeBufferArray(scip, &lincoefs);
      SCIPfreeBufferArray(scip, &linvars);
      SCIPfreeBufferArray(scip, &coefs);
      SCIPfreeBufferArray(scip, &vars);
   }

   /* delete unused information in constraint handler data */
   SCIP_CALL( correctConshdlrdata(scip, conshdlrdata, ndelconss) );

   /* return the correct result code */
   if( cutoff )
      *result = SCIP_CUTOFF;
   else if( *nfixedvars > oldnfixedvars || *naggrvars > oldnaggrvars || *nchgbds > oldnchgbds || *ndelconss > oldndelconss
      || *nupgdconss > oldnupgdconss || *nchgcoefs > oldnchgcoefs || *nchgsides > oldnchgsides )
      *result = SCIP_SUCCESS;
   else
      *result = SCIP_DIDNOTFIND;

   return SCIP_OKAY;
}

/** variable rounding lock method of constraint handler */
static
SCIP_DECL_CONSLOCK(consLockPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSDATA* consdata;
   SCIP_Real lhs;
   SCIP_Real rhs;
   SCIP_Bool haslhs;
   SCIP_Bool hasrhs;
   int v;
   int c;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(locktype == SCIP_LOCKTYPE_MODEL);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   lhs = consdata->lhs;
   rhs = consdata->rhs;
   assert(!SCIPisInfinity(scip, lhs));
   assert(!SCIPisInfinity(scip, -rhs));
   assert(SCIPisLE(scip, lhs, rhs));

   haslhs = !SCIPisInfinity(scip, -lhs);
   hasrhs = !SCIPisInfinity(scip, rhs);

   SCIPdebugMsg(scip, "%socking constraint <%s> by [%d;%d].\n", (nlocksneg < 0) || (nlockspos < 0) ? "Unl" : "L", SCIPconsGetName(cons), nlocksneg, nlockspos);

   /* update rounding locks of every single variable corresponding to the and-constraints */
   for( c = consdata->nconsanddatas - 1; c >= 0; --c )
   {
      SCIP_VAR* andres;
      SCIP_VAR** andvars;
      SCIP_Real val;
      int nandvars;
      SCIP_CONS* andcons;
      CONSANDDATA* consanddata;

      consanddata = consdata->consanddatas[c];
      assert( consanddata != NULL );

      if( !consanddata->istransformed )
         continue;

      andcons = consanddata->cons;

      if( andcons == NULL )
      {
         /* we should have no new variables */
         assert(consanddata->nnewvars == 0);
         assert(consanddata->nvars == 0);

         SCIPfreeBlockMemoryArrayNull(scip, &(consanddata->vars), consanddata->svars);
         SCIPfreeBlockMemoryArrayNull(scip, &(consanddata->newvars), consanddata->snewvars);

         consanddata->nvars = 0;
         consanddata->svars = 0;
         consanddata->nnewvars = 0;
         consanddata->snewvars = 0;
         consanddata->istransformed = FALSE;

         continue;
      }
      assert(andcons != NULL);
      if( consanddata->nnewvars > 0 )
      {
         andvars = consanddata->newvars;
         nandvars = consanddata->nnewvars;
      }
      else
      {
         andvars = consanddata->vars;
         nandvars = consanddata->nvars;
      }
      assert(andvars != NULL || nandvars == 0);

      /* probably we need to store the resultant too, now it's not possible to remove the resultant from the and-constraint */
      andres = SCIPgetResultantAnd(scip, andcons);
      assert(andres != NULL);

      val = consdata->andnegs[c] ? -consdata->andcoefs[c] : consdata->andcoefs[c];

      /* lock variables */
      if( SCIPisPositive(scip, val) )
      {
         if( haslhs )
         {
            for( v = nandvars - 1; v >= 0; --v )
            {
               SCIP_CALL( SCIPaddVarLocksType(scip, andvars[v], locktype, nlockspos, nlocksneg) );
            }
            SCIP_CALL( SCIPaddVarLocksType(scip, andres, locktype, nlocksneg + nlockspos, nlocksneg + nlockspos) );

            SCIP_CALL( checkLocksAndRes(scip, andres) );
         }
         if( hasrhs )
         {
            for( v = nandvars - 1; v >= 0; --v )
            {
               SCIP_CALL( SCIPaddVarLocksType(scip, andvars[v], locktype, nlocksneg, nlockspos) );
            }
            /* don't double the locks on the and-resultant */
            if( !haslhs )
            {
               SCIP_CALL( SCIPaddVarLocksType(scip, andres, locktype, nlocksneg + nlockspos, nlocksneg + nlockspos) );

               SCIP_CALL( checkLocksAndRes(scip, andres) );
            }
         }
      }
      else
      {
         if( haslhs )
         {
            for( v = nandvars - 1; v >= 0; --v )
            {
               SCIP_CALL( SCIPaddVarLocksType(scip, andvars[v], locktype, nlocksneg, nlockspos) );
            }
            SCIP_CALL( SCIPaddVarLocksType(scip, andres, locktype, nlocksneg + nlockspos, nlocksneg + nlockspos) );

            SCIP_CALL( checkLocksAndRes(scip, andres) );
         }
         if( hasrhs )
         {
            for( v = nandvars - 1; v >= 0; --v )
            {
               SCIP_CALL( SCIPaddVarLocksType(scip, andvars[v], locktype, nlockspos, nlocksneg) );
            }
            /* don't double the locks on the and-resultant */
            if( !haslhs )
            {
               SCIP_CALL( SCIPaddVarLocksType(scip, andres, locktype, nlocksneg + nlockspos, nlocksneg + nlockspos) );

               SCIP_CALL( checkLocksAndRes(scip, andres) );
            }
         }
      }
   }

   return SCIP_OKAY;
}

/** constraint display method of constraint handler
 *
 *  @warning The linear-and-reformulation is part of the model and is separately printed by other constraint handlers
 */
static
SCIP_DECL_CONSPRINT(consPrintPseudoboolean)
{  /*lint --e{715}*/
   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
   assert(cons != NULL);

   SCIP_CALL( consdataPrint(scip, cons, file) );

   return SCIP_OKAY;
}

/** constraint copying method of constraint handler */
static
SCIP_DECL_CONSCOPY(consCopyPseudoboolean)
{  /*lint --e{715}*/
   const char* consname;

   assert(scip != NULL);
   assert(sourcescip != NULL);
   assert(sourcecons != NULL);

   if( name != NULL )
      consname = name;
   else
      consname = SCIPconsGetName(sourcecons);

   SCIP_CALL( copyConsPseudoboolean(scip, cons, sourcescip, sourcecons, consname, varmap, consmap,
         initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global,
         valid) );
   assert(cons != NULL || *valid == FALSE);

   return SCIP_OKAY;
}

/** constraint parsing method of constraint handler
 *
 *  @warning The linear-and-reformulation is added even if equivalent variables and constraints are part of the model
 */
static
SCIP_DECL_CONSPARSE(consParsePseudoboolean)
{  /*lint --e{715}*/
   SCIP_VAR*** monomialvars;
   SCIP_VAR*** terms;
   SCIP_VAR** linvars;
   SCIP_VAR* indvar;
   SCIP_Real** monomialexps;
   SCIP_Real* monomialcoefs;
   SCIP_Real* termvals;
   SCIP_Real* linvals;
   SCIP_Real weight;
   SCIP_Real lhs;
   SCIP_Real rhs;
   SCIP_Bool issoftcons;
   const char* endptr;
   const char* firstcomp;
   const char* secondcomp;
   const char* lhsstrptr;
   const char* rhsstrptr;
   const char* varstrptr;
   char* polynomialstr;
   int* monomialnvars;
   int* ntermvars;
   int polynomialsize;
   int nmonomials;
   int nterms;
   int nlinvars;
   int i;
   int j;

   assert(scip != NULL);
   assert(success != NULL);
   assert(str != NULL);
   assert(name != NULL);
   assert(cons != NULL);

   *success = FALSE;

   /* ignore whitespace */
   SCIP_CALL( SCIPskipSpace((char**)&str) );

   /* return of string empty */
   if( !(*str) )
      return SCIP_OKAY;

   /* find comparators in the line first, all other remaining parsing depends on occurence of
    * the comparators '<=', '>=', '==', and the special word [free]
    */
   firstcomp = NULL;
   secondcomp = NULL;
   endptr = str;

   /* loop over the input string to find all comparators */
   while( *endptr )
   {
      SCIP_Bool found = FALSE;
      int increment = 1;

      /* try if we found a possible comparator */
      switch( endptr[0] )
      {
      case '<':
      case '=':
      case '>':
         /* check if the two characters endptr[0,1] form a comparator together */
         if( endptr[1] == '=' )
         {
            found = TRUE;

            /* update increment to continue after this comparator */
            increment = 2;
         }
         break;
      case '[':
         if( strncmp(endptr, "[free]", 6) == 0 )
         {
            found = TRUE;

            /* update increment to continue after this comparator */
            increment = 6;
         }
         break;
      default:
         break;
      }

      /* assign the found comparator to the first or second pointer and check for syntactical violations */
      if( found )
      {
         if( firstcomp == NULL )
         {
            firstcomp = endptr;
         }
         else
         {
            if( secondcomp != NULL )
            {
               SCIPerrorMessage("Found more than two comparators in line %s\n", str);
               return SCIP_OKAY;
            }
            else if( strncmp(firstcomp, "<=", 2) != 0 )
            {
               SCIPerrorMessage("Two comparators in line that do not range: %s", str);
               return SCIP_OKAY;
            }
            else if( strncmp(endptr, "<=", 2) != 0 )
            {
               SCIPerrorMessage("Bad second comparator, expected ranged specification: %s", str);
               return SCIP_OKAY;
            }

            secondcomp = endptr;
         }
      }

      endptr += increment;
   }

   /* check if we did find at least one comparator */
   if( firstcomp == NULL )
   {
      SCIPerrorMessage("Could not find any comparator in line %s\n", str);
      return SCIP_OKAY;
   }

   /* initialize side pointers to the free state */
   lhsstrptr = NULL;
   rhsstrptr = NULL;
   varstrptr = str;

   /* assign the strings for parsing the left hand side, right hand side, and pseudoboolean polynomial */
   switch( *firstcomp )
   {
      case '<':
         assert(firstcomp[1] == '=');
         /* we have ranged row lhs <= ... <= rhs */
         if( secondcomp != NULL )
         {
            assert(secondcomp[0] == '<' && secondcomp[1] == '=');
            lhsstrptr = str;
            rhsstrptr = secondcomp + 2;
            varstrptr = firstcomp + 2;
         }
         /* we have an inequality with infinite left hand side ... <= rhs */
         else
            rhsstrptr = firstcomp + 2;
         break;
      case '>':
         assert(firstcomp[1] == '=');
         assert(secondcomp == NULL);
         /* we have ... >= lhs */
         lhsstrptr = firstcomp + 2;
         break;
      case '=':
         assert(firstcomp[1] == '=');
         assert(secondcomp == NULL);
         /* we have ... == lhs (rhs) */
         rhsstrptr = firstcomp + 2;
         lhsstrptr = firstcomp + 2;
         break;
      case '[':
         assert(strncmp(firstcomp, "[free]", 6) == 0);
         assert(secondcomp == NULL);
         /* we have ... [free] */
         endptr = firstcomp + 6;
         break;
      default:
         /* it should not be possible that a different character appears in that position */
         SCIPerrorMessage("Parsing has wrong comparator character '%c', should be one of <=>[", *firstcomp);
         return SCIP_READERROR;
   }

   /* initialize sides to the free state */
   lhs = -SCIPinfinity(scip);
   rhs =  SCIPinfinity(scip);

   /* parse left hand side, if necessary */
   if( lhsstrptr != NULL )
   {
      if( !SCIPparseReal(scip, lhsstrptr, &lhs, (char**)&endptr) )
      {
         SCIPerrorMessage("error parsing left hand side number from <%s>\n", lhsstrptr);
         return SCIP_OKAY;
      }

      /* in case of an equation, assign the left also to the right hand side */
      if( rhsstrptr == lhsstrptr )
         rhs = lhs;
   }

   /* parse right hand side, if different from left hand side */
   if( rhsstrptr != NULL && rhsstrptr != lhsstrptr )
   {
      if( !SCIPparseReal(scip, rhsstrptr, &rhs, (char**)&endptr) )
      {
         SCIPerrorMessage("error parsing right hand side number from <%s>\n", lhsstrptr);
         return SCIP_OKAY;
      }
   }

   /* initialize indicator data to the hard state */
   indvar = NULL;
   weight = 0.0;
   issoftcons = FALSE;

   /* skip white spaces */
   SCIP_CALL( SCIPskipSpace((char**)&endptr) );
   str = endptr;

   /* parse indicator variable, should look like (indvar = var) */
   if( *endptr == '(' )
   {
      endptr = strchr(endptr + 1, '=');

      if( endptr == NULL )
      {
         SCIPerrorMessage("variable assignment missing in '%s'\n", str);
         return SCIP_OKAY;
      }

      /* parse variable name */
      SCIP_CALL( SCIPparseVarName(scip, endptr + 1, &indvar, (char**)&endptr) );

      if( indvar == NULL )
      {
         SCIPerrorMessage("indicator variable not found in '%s'\n", str);
         return SCIP_OKAY;
      }

      /* parse closing parenthesis */
      endptr = strchr(endptr, ')');

      if( endptr == NULL )
      {
         SCIPerrorMessage("closing parenthesis missing in '%s'\n", str);
         return SCIP_OKAY;
      }

      weight = SCIPvarGetObj(indvar);
      issoftcons = TRUE;
   }

   /* initialize polynomial string */
   polynomialsize = (int)(MAX(firstcomp, secondcomp) + 1 - varstrptr);
   SCIP_CALL( SCIPallocBufferArray(scip, &polynomialstr, polynomialsize) );
   (void)SCIPstrncpy(polynomialstr, varstrptr, polynomialsize);

   /* parse pseudoboolean polynomial */
   SCIP_CALL( SCIPparseVarsPolynomial(scip, polynomialstr, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, (char**)&endptr, success) );

   /* free polynomial string */
   polynomialsize -= (int)(endptr + 1 - polynomialstr);
   SCIPfreeBufferArray(scip, &polynomialstr);

   /* check polynomial syntax */
   if( !(*success) )
   {
      SCIPerrorMessage("no luck in parsing pseudoboolean polynomial '%s'\n", varstrptr);
      return SCIP_OKAY;
   }
   else if( polynomialsize >= 1 )
   {
      SCIPerrorMessage("no completion of parsing pseudoboolean polynomial '%s'\n", varstrptr);
      SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
      *success = FALSE;
      return SCIP_OKAY;
   }

   /* initialize buffers for storing the terms and coefficients */
   SCIP_CALL( SCIPallocBufferArray(scip, &terms, nmonomials) );
   SCIP_CALL( SCIPallocBufferArray(scip, &termvals, nmonomials) );
   SCIP_CALL( SCIPallocBufferArray(scip, &ntermvars, nmonomials) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nmonomials) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nmonomials) );

   nterms = 0;
   nlinvars = 0;

   /* separate linear terms */
   for( i = 0; i < nmonomials; ++i )
   {
      if( SCIPisZero(scip, monomialcoefs[i]) )
         continue;

      ntermvars[nterms] = 0;

      /* collect relevant variables */
      for( j = 0; j < monomialnvars[i]; ++j )
      {
         if( monomialexps[i][j] < 0.0 )
         {
            SCIPerrorMessage("invalid exponent '%f' on variable <%s> in pseudoboolean polynomial '%s'\n", monomialexps[i][j], SCIPvarGetName(monomialvars[i][j]), varstrptr);
            goto TERMINATE;
         }

         if( monomialexps[i][j] == 0.0 )
            continue;

         monomialvars[i][ntermvars[nterms]++] = monomialvars[i][j];
      }

      if( ntermvars[nterms] > 1 )
      {
         terms[nterms] = monomialvars[i];
         termvals[nterms] = monomialcoefs[i];
         ++nterms;
      }
      else if( ntermvars[nterms] == 1 )
      {
         if( issoftcons && ( monomialvars[i][0] == indvar || SCIPvarGetNegatedVar(monomialvars[i][0]) == indvar ) )
         {
            SCIPerrorMessage("indicator variable <%s> part of indicated constraint '%s'\n", SCIPvarGetName(indvar), varstrptr);
            goto TERMINATE;
         }

         linvars[nlinvars] = monomialvars[i][0];
         linvals[nlinvars] = monomialcoefs[i];
         ++nlinvars;
      }
      else
      {
         assert(ntermvars[nterms] == 0);

         if( !SCIPisInfinity(scip, -lhs) )
            lhs -= monomialcoefs[i];

         if( !SCIPisInfinity(scip, rhs) )
            rhs -= monomialcoefs[i];
      }
   }

   /* create pseudoboolean constraint */
   SCIP_CALL( SCIPcreateConsPseudoboolean(scip, cons, name, linvars, nlinvars, linvals, terms, nterms, ntermvars,
         termvals, indvar, weight, issoftcons, lhs, rhs, initial, separate, enforce, check, propagate, local,
         modifiable, dynamic, removable, stickingatnode) );

TERMINATE:
   /* free buffers for storing the terms and coefficients */
   SCIPfreeBufferArray(scip, &linvals);
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &ntermvars);
   SCIPfreeBufferArray(scip, &termvals);
   SCIPfreeBufferArray(scip, &terms);

   /* free pseudoboolean polynomial */
   SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);

   return SCIP_OKAY;
}

/** constraint method of constraint handler which returns the variables (if possible) */
static
SCIP_DECL_CONSGETVARS(consGetVarsPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONSDATA* consdata;
   CONSANDDATA* consanddata;
   SCIP_VAR** linconsvars;
   SCIP_VAR** linvars;
   SCIP_VAR** andress;
   int nlinconsvars;
   int nlinvars;
   int nandress;
   SCIP_Bool transformed;
   int nvars;
   int r;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(cons != NULL);
   assert(vars != NULL);
   assert(success != NULL);

   if( varssize < 0 )
      return SCIP_INVALIDDATA;
   assert(varssize >= 0);

   *success = TRUE;

   /* pseudoboolean constraint is already deleted */
   if( SCIPconsIsDeleted(cons) )
   {
      vars = NULL;

      return SCIP_OKAY; /*lint !e438*/
   }

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   assert(consdata->lincons != NULL);

   /* linear constraint of pseudoboolean is already deleted */
   if( SCIPconsIsDeleted(consdata->lincons) )
   {
      vars = NULL;

      return SCIP_OKAY; /*lint !e438*/
   }

   /* gets number of variables in linear constraint */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nlinconsvars) );
   assert(nlinconsvars >= 0);

   /* no variables exist */
   if( nlinconsvars == 0 )
   {
      vars = NULL;

      return SCIP_OKAY; /*lint !e438*/
   }
   /* not enough space in the variables array */
   else if( varssize < nlinconsvars )
   {
      (*success) = FALSE;

      return SCIP_OKAY;
   }

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &linconsvars, nlinconsvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nlinconsvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andress, nlinconsvars) );

   /* get variables and coefficient of linear constraint */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, linconsvars, NULL, &nlinconsvars) );

   /* calculate all non-artificial linear variables and all artificial and-resultants */
   SCIP_CALL( getLinVarsAndAndRess(scip, cons, linconsvars, NULL, nlinconsvars, linvars, NULL, &nlinvars,
         andress, NULL, NULL, &nandress) );
   assert(nlinconsvars == nlinvars + nandress);

   nvars = nlinvars;

   if( nlinvars > 0 )
   {
      assert(linvars != NULL);
      BMScopyMemoryArray(vars, linvars, nvars);
   }

   if( nandress == 0 )
      goto TERMINATE;

   assert(andress != NULL);

   /* get constraint handler data */
   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);
   assert(conshdlrdata->hashmap != NULL);

   transformed = SCIPconsIsTransformed(cons);

   for( r = nandress - 1; r >= 0; --r )
   {
      SCIP_CONS* andcons;

      assert(andress[r] != NULL);

      consanddata = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)andress[r]);

      assert(consanddata != NULL);
      assert(consanddata->istransformed);

      if( transformed )
         andcons = consanddata->cons;
      else
         andcons = consanddata->origcons;

      assert(andcons != NULL);

      /* not enough space for all variables */
      if( varssize <= nvars )
      {
         (*success) = FALSE;

         goto TERMINATE;
      }

      /* add the resultant */
      vars[nvars] = andress[r];
      ++nvars;

      /* add all and-operands and the resultant */
      if( !SCIPconsIsDeleted(andcons) )
      {
         int noperands = SCIPgetNVarsAnd(scip, andcons);

         assert(noperands >= 0);

         /* not enough space for all variables */
         if( varssize < nvars + noperands )
         {
            (*success) = FALSE;

            goto TERMINATE;
         }

         /* copy operands */
         if( noperands > 0 )
         {
            assert(SCIPgetVarsAnd(scip, andcons) != NULL);
            BMScopyMemoryArray(&(vars[nvars]), SCIPgetVarsAnd(scip, andcons), noperands); /*lint !e866*/
            nvars += noperands;
         }
      }
   }

 TERMINATE:

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &andress);
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &linconsvars);

   return SCIP_OKAY;
}

/** constraint method of constraint handler which returns the number of variables (if possible) */
static
SCIP_DECL_CONSGETNVARS(consGetNVarsPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONSDATA* consdata;
   CONSANDDATA* consanddata;
   SCIP_VAR** linconsvars;
   SCIP_VAR** linvars;
   SCIP_VAR** andress;
   int nlinconsvars;
   int nlinvars;
   int nandress;
   SCIP_Bool transformed;
   int r;

   assert(scip != NULL);
   assert(conshdlr != NULL);
   assert(cons != NULL);
   assert(nvars != NULL);
   assert(success != NULL);

   (*success) = TRUE;

   /* pseudoboolean constraint is already deleted */
   if( SCIPconsIsDeleted(cons) )
   {
      *nvars = 0;

      return SCIP_OKAY;
   }

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);
   assert(consdata->lincons != NULL);

   /* linear constraint of pseudoboolean is already deleted */
   if( SCIPconsIsDeleted(consdata->lincons) )
   {
      *nvars = 0;

      return SCIP_OKAY;
   }

   /* gets number of variables in linear constraint */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nlinconsvars) );
   assert(nlinconsvars >= 0);

   /* no variables exist */
   if( nlinconsvars == 0 )
   {
      *nvars = 0;

      return SCIP_OKAY;
   }

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &linconsvars, nlinconsvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nlinconsvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andress, nlinconsvars) );

   /* get variables and coefficient of linear constraint */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, linconsvars, NULL, &nlinconsvars) );

   /* calculate all non-artificial linear variables and all artificial and-resultants */
   SCIP_CALL( getLinVarsAndAndRess(scip, cons, linconsvars, NULL, nlinconsvars, linvars, NULL, &nlinvars,
         andress, NULL, NULL, &nandress) );
   assert(nlinconsvars == nlinvars + nandress);

   *nvars = nlinvars;

   if( nandress == 0 )
      goto TERMINATE;

   assert(andress != NULL);

   /* get constraint handler data */
   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);
   assert(conshdlrdata->hashmap != NULL);

   transformed = SCIPconsIsTransformed(cons);

   for( r = nandress - 1; r >= 0; --r )
   {
      SCIP_CONS* andcons;

      assert(andress[r] != NULL);

      consanddata = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)andress[r]);

      assert(consanddata != NULL);
      assert(consanddata->istransformed);

      if( transformed )
         andcons = consanddata->cons;
      else
         andcons = consanddata->origcons;

      assert(andcons != NULL);

      if( SCIPconsIsDeleted(andcons) )
      {
         /* only add one for the resultant */
         ++(*nvars);
      }
      else
      {
         /* add all and-operands and one for the resultant */
         *nvars += SCIPgetNVarsAnd(scip, andcons) + 1;
      }
   }

 TERMINATE:
   /* free temporary memory */
   SCIPfreeBufferArray(scip, &andress);
   SCIPfreeBufferArray(scip, &linvars);
   SCIPfreeBufferArray(scip, &linconsvars);

   return SCIP_OKAY;
}

/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
static
SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );

   return SCIP_OKAY;
}

/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
static
SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphPseudoboolean)
{  /*lint --e{715}*/
   SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );

   return SCIP_OKAY;
}

/*
 * constraint specific interface methods
 */

/** creates the handler for pseudoboolean constraints and includes it in SCIP */
SCIP_RETCODE SCIPincludeConshdlrPseudoboolean(
   SCIP*                 scip                /**< SCIP data structure */
   )
{
   SCIP_CONSHDLR* conshdlr;
   SCIP_CONSHDLRDATA* conshdlrdata;

   /* create pseudoboolean constraint handler data */
   SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata) );

   /* include constraint handler */
   SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
         CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
         consEnfolpPseudoboolean, consEnfopsPseudoboolean, consCheckPseudoboolean, consLockPseudoboolean,
         conshdlrdata) );
   assert(conshdlr != NULL);

   /* set non-fundamental callbacks via specific setter functions */
   SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyPseudoboolean, consCopyPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeletePseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreePseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParsePseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitprePseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolPseudoboolean, CONSHDLR_MAXPREROUNDS,
         CONSHDLR_PRESOLTIMING) );
   SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphPseudoboolean) );
   SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphPseudoboolean) );

   /* add pseudoboolean constraint handler parameters */
   SCIP_CALL( SCIPaddBoolParam(scip,
         "constraints/" CONSHDLR_NAME "/decomposenormal",
         "decompose every normal pseudo boolean constraint into a \"linear\" constraint and \"and\" constraints",
         &conshdlrdata->decomposenormalpbcons, TRUE, DEFAULT_DECOMPOSENORMALPBCONS, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(scip,
         "constraints/" CONSHDLR_NAME "/decomposeindicator",
         "decompose every soft pseudo boolean constraint into \"indicator\" constraints and \"and\" constraints",
         &conshdlrdata->decomposeindicatorpbcons, TRUE, DEFAULT_DECOMPOSEINDICATORPBCONS, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(scip,
         "constraints/" CONSHDLR_NAME "/nlcseparate", "should the nonlinear constraints be separated during LP processing?",
         NULL, TRUE, DEFAULT_SEPARATENONLINEAR, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(scip,
         "constraints/" CONSHDLR_NAME "/nlcpropagate", "should the nonlinear constraints be propagated during node processing?",
         NULL, TRUE, DEFAULT_PROPAGATENONLINEAR, NULL, NULL) );
   SCIP_CALL( SCIPaddBoolParam(scip,
         "constraints/" CONSHDLR_NAME "/nlcremovable", "should the nonlinear constraints be removable?",
         NULL, TRUE, DEFAULT_REMOVABLENONLINEAR, NULL, NULL) );

#ifdef NONLINCONSUPGD_PRIORITY
   /* include the quadratic constraint upgrade in the nonlinear constraint handler */
   SCIP_CALL( SCIPincludeNonlinconsUpgrade(scip, nonlinconsUpgdPseudoboolean, NULL, NONLINCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
#endif

   return SCIP_OKAY;
}

/** creates and captures a pseudoboolean constraint, with given linear and and-constraints */
SCIP_RETCODE SCIPcreateConsPseudobooleanWithConss(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
   const char*           name,               /**< name of constraint */
   SCIP_CONS*            lincons,            /**< associated linear constraint */
   SCIP_LINEARCONSTYPE   linconstype,        /**< linear constraint type of associated linear constraint */
   SCIP_CONS**           andconss,           /**< associated and-constraints */
   SCIP_Real*            andcoefs,           /**< associated coefficients of and-constraints */
   int                   nandconss,          /**< number of associated and-constraints */
   SCIP_VAR*             indvar,             /**< indicator variable if it's a soft constraint, or NULL */
   SCIP_Real             weight,             /**< weight of the soft constraint, if it is one */
   SCIP_Bool             issoftcons,         /**< is this a soft constraint */
   SCIP_Real             lhs,                /**< left hand side of constraint */
   SCIP_Real             rhs,                /**< right hand side of constraint */
   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
                                              *   Usually set to TRUE. */
   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
                                              *   Usually set to TRUE. */
   SCIP_Bool             local,              /**< is constraint only valid locally?
                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
                                              *   adds coefficients to this constraint. */
   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
                                              *   Usually set to FALSE. Set to TRUE for own cuts which
                                              *   are seperated as constraints. */
   SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
   SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
                                              *   if it may be moved to a more global node?
                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
   )
{
   CONSANDDATA* newdata;
   CONSANDDATA* tmpdata;
   SCIP_CONSHDLR* conshdlr;
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONSDATA* consdata;
   SCIP_VAR** vars;
   SCIP_VAR* res;
   SCIP_Bool memisinvalid;
   SCIP_Bool transformed;
   int nvars;
   int c;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(lincons != NULL);
   assert(linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
   assert(andconss != NULL || nandconss == 0);
   assert(andcoefs != NULL || nandconss == 0);
   assert(issoftcons == (indvar != NULL));

   /* find the pseudoboolean constraint handler */
   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
   if( conshdlr == NULL )
   {
      SCIPerrorMessage("pseudo boolean constraint handler not found\n");
      return SCIP_PLUGINNOTFOUND;
   }

   if( isnan(lhs) || isnan(rhs) )
   {
      SCIPerrorMessage("%s hand side of pseudo boolean constraint <%s> is nan\n",
            isnan(lhs) ? "left" : "right", name);
      return SCIP_INVALIDDATA;
   }

   if( issoftcons )
   {
      if( modifiable )
      {
         SCIPerrorMessage("soft pseudo boolean constraint <%s> must not be modifiable because the implemented formulation requires finite activity bounds\n", name);
         return SCIP_INVALIDDATA;
      }

      if( isnan(weight) )
      {
         SCIPerrorMessage("weight of pseudo boolean constraint <%s> is nan\n", name);
         return SCIP_INVALIDDATA;
      }
   }

   /* get constraint handler data */
   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   /* initial hashmap and -table */
   SCIP_CALL( inithashmapandtable(scip, &conshdlrdata) );

   assert(conshdlrdata->hashmap != NULL);
   assert(conshdlrdata->hashtable != NULL);
   assert(conshdlrdata->allconsanddatas != NULL);
   assert(conshdlrdata->nallconsanddatas <= conshdlrdata->sallconsanddatas);

   memisinvalid = TRUE;
   newdata = NULL;

   transformed = SCIPconsIsTransformed(lincons);

   /* create hash map and hash table entries */
   for( c = nandconss - 1; c >= 0; --c )
   {
      assert(andconss[c] != NULL);
      res = SCIPgetResultantAnd(scip, andconss[c]);
      vars = SCIPgetVarsAnd(scip, andconss[c]);
      nvars = SCIPgetNVarsAnd(scip, andconss[c]);
      assert(vars != NULL && nvars > 0);
      assert(res != NULL);

      /* stop if the constraint has 0 variables or an error occurred (coverity issue) */
      if( nvars <= 0 )
         continue;

      /* if allocated memory in this for loop was already used, allocate a new block, otherwise we only need to copy the variables */
      if( memisinvalid )
      {
         /* allocate memory for a possible new consanddata object */
         SCIP_CALL( SCIPallocBlockMemory(scip, &newdata) );
         SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(newdata->vars), vars, nvars) );
         newdata->svars = nvars;
         newdata->newvars = NULL;
         newdata->nnewvars = 0;
         newdata->snewvars = 0;
         newdata->istransformed = transformed;
         newdata->isoriginal = !transformed;
         newdata->noriguses = 0;
         newdata->nuses = 0;
         newdata->cons = NULL;
         newdata->origcons = NULL;
      }
      else
      {
         assert(newdata != NULL);
         /* resize variable array if necessary */
         if( newdata->svars < nvars )
         {
            SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(newdata->vars), &(newdata->svars), nvars) );
         }

         /* copy variables in already allocated array */
         BMScopyMemoryArray(newdata->vars, vars, nvars);
      }

      /* sort variables */
      SCIPsortPtr((void**)(newdata->vars), SCIPvarComp, nvars);

      newdata->nvars = nvars;
      assert(newdata->vars != NULL && newdata->nvars > 0);

      if( SCIPconsIsTransformed(andconss[c]) )
      {
         int v;

         /* either all constraints are transformed or none */
         assert(transformed);
         newdata->cons = andconss[c];

         /* capture all variables */
         for( v = newdata->nvars - 1; v >= 0; --v )
         {
            SCIP_CALL( SCIPcaptureVar(scip, newdata->vars[v]) ); /*lint !e613*/
         }
      }
      else
      {
         /* either all constraints are transformed or none */
         assert(!transformed);
         newdata->origcons = andconss[c];
      }

      /* get constraint from current hash table with same variables as andconss[c] */
      tmpdata = (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)newdata));
      assert(tmpdata == NULL || tmpdata->cons != NULL || tmpdata->origcons != NULL);

      if( tmpdata == NULL || (tmpdata->cons != andconss[c] && tmpdata->origcons != andconss[c]))
      {
         if( tmpdata != NULL && (tmpdata->cons != NULL || tmpdata->origcons != NULL) )
         {
            SCIPwarningMessage(scip, "Another and-constraint with the same variables but different and-resultant is added to the global and-constraint hashtable of pseudoboolean constraint handler.\n");
         }

         /* resize data for all and-constraints if necessary */
         if( conshdlrdata->nallconsanddatas == conshdlrdata->sallconsanddatas )
         {
            SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(conshdlrdata->allconsanddatas), &(conshdlrdata->sallconsanddatas), SCIPcalcMemGrowSize(scip, conshdlrdata->sallconsanddatas + 1)) );
         }

         conshdlrdata->allconsanddatas[conshdlrdata->nallconsanddatas] = newdata;
         ++(conshdlrdata->nallconsanddatas);

         /* no such and-constraint in current hash table: insert the new object into hash table */
         SCIP_CALL( SCIPhashtableInsert(conshdlrdata->hashtable, (void*)newdata) );

         /* if newdata object was new we want to allocate new memory in next loop iteration */
         memisinvalid = TRUE;
         assert(!SCIPhashmapExists(conshdlrdata->hashmap, (void*)res));

         /* capture and-constraint */
         if( transformed )
         {
            SCIP_CALL( SCIPcaptureCons(scip, newdata->cons) );

            /* lock upgrade to keep control */
            SCIPconsAddUpgradeLocks(newdata->cons, +1);

            /* initialize usage of data object */
            newdata->nuses = 1;
         }
         else
         {
            SCIP_CALL( SCIPcaptureCons(scip, newdata->origcons) );

            /* initialize usage of data object */
            newdata->noriguses = 1;
         }

         /* insert new mapping */
         assert(!SCIPhashmapExists(conshdlrdata->hashmap, (void*)res));
         SCIP_CALL( SCIPhashmapInsert(conshdlrdata->hashmap, (void*)res, (void*)newdata) );
      }
      else
      {
         assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)res));
         memisinvalid = FALSE;

         if( transformed )
         {
            assert(tmpdata->nuses > 0);

            /* increase usage of data object */
            ++(tmpdata->nuses);
         }
         else
         {
            assert(tmpdata->noriguses > 0);

            /* increase usage of data object */
            ++(tmpdata->noriguses);
         }
      }
   }

   if( !memisinvalid )
   {
      assert(newdata != NULL);

      /* free temporary memory */
      SCIPfreeBlockMemoryArray(scip, &(newdata->vars), newdata->svars);
      SCIPfreeBlockMemory(scip, &newdata);
   }

   /* adjust right hand side */
   if( SCIPisInfinity(scip, rhs) )
      rhs = SCIPinfinity(scip);
   else if( SCIPisInfinity(scip, -rhs) )
      rhs = -SCIPinfinity(scip);

   /* capture linear constraint */
   SCIP_CALL( SCIPcaptureCons(scip, lincons) );

   /* @todo: make the constraint upgrade flag global, now it works only for the common linear constraint */
   /* mark linear constraint not to be upgraded - otherwise we loose control over it */
   SCIPconsAddUpgradeLocks(lincons, +1);

   /* create constraint data */
   /* checking for and-constraints will be FALSE, we check all information in this constraint handler */
   SCIP_CALL( consdataCreate(scip, conshdlr, &consdata, lincons, linconstype, andconss, andcoefs, NULL, nandconss,
         indvar, weight, issoftcons, lhs, rhs, check, FALSE) );
   assert(consdata != NULL);

   /* create constraint */
   SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
         local, modifiable, dynamic, removable, stickingatnode) );

   return SCIP_OKAY;
}

/** creates and captures a pseudoboolean constraint
 *
 *  @note linear and nonlinear terms can be added using SCIPaddCoefPseudoboolean() and SCIPaddTermPseudoboolean(),
 *        respectively
 *
 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
 */
SCIP_RETCODE SCIPcreateConsPseudoboolean(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
   const char*           name,               /**< name of constraint */
   SCIP_VAR**            linvars,            /**< variables of the linear part, or NULL */
   int                   nlinvars,           /**< number of variables of the linear part */
   SCIP_Real*            linvals,            /**< coefficients of linear part, or NULL */
   SCIP_VAR***           terms,              /**< nonlinear terms of variables, or NULL */
   int                   nterms,             /**< number of terms of variables of nonlinear term */
   int*                  ntermvars,          /**< number of variables in nonlinear terms, or NULL */
   SCIP_Real*            termvals,           /**< coefficients of nonlinear parts, or NULL */
   SCIP_VAR*             indvar,             /**< indicator variable if it's a soft constraint, or NULL */
   SCIP_Real             weight,             /**< weight of the soft constraint, if it is one */
   SCIP_Bool             issoftcons,         /**< is this a soft constraint */
   SCIP_Real             lhs,                /**< left hand side of constraint */
   SCIP_Real             rhs,                /**< right hand side of constraint */
   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
                                              *   Usually set to TRUE. */
   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
                                              *   Usually set to TRUE. */
   SCIP_Bool             local,              /**< is constraint only valid locally?
                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
                                              *   adds coefficients to this constraint. */
   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
                                              *   Usually set to FALSE. Set to TRUE for own cuts which
                                              *   are separated as constraints. */
   SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
   SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
                                              *   if it may be moved to a more global node?
                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
   )
{
   SCIP_CONSHDLRDATA* conshdlrdata;
   SCIP_CONSHDLR* conshdlr;
   SCIP_CONSDATA* consdata;
   SCIP_VAR** andress;
   SCIP_CONS** andconss;
   SCIP_Real* andcoefs;
   SCIP_Bool* andnegs;
   int nandconss;
   SCIP_CONS* lincons;
   SCIP_LINEARCONSTYPE linconstype;
   int c;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(linvars != NULL || nlinvars == 0);
   assert(linvals != NULL || nlinvars == 0);
   assert(terms != NULL || nterms == 0);
   assert(termvals != NULL || nterms == 0);
   assert(ntermvars != NULL || nterms == 0);
   assert(issoftcons == (indvar != NULL));

   /* find the pseudoboolean constraint handler */
   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
   if( conshdlr == NULL )
   {
      SCIPerrorMessage("pseudo boolean constraint handler not found\n");
      return SCIP_PLUGINNOTFOUND;
   }

   if( isnan(lhs) || isnan(rhs) )
   {
      SCIPerrorMessage("%s hand side of pseudo boolean constraint <%s> is nan\n",
            isnan(lhs) ? "left" : "right", name);
      return SCIP_INVALIDDATA;
   }

   if( issoftcons )
   {
      if( modifiable )
      {
         SCIPerrorMessage("soft pseudo boolean constraint <%s> must not be modifiable because the implemented formulation requires finite activity bounds\n", name);
         return SCIP_INVALIDDATA;
      }

      if( isnan(weight) )
      {
         SCIPerrorMessage("weight of pseudo boolean constraint <%s> is nan\n", name);
         return SCIP_INVALIDDATA;
      }
   }

   for( c = 0; c < nlinvars; ++c )
   {
      if( !SCIPisFinite(linvals[c]) || SCIPisInfinity(scip, REALABS(linvals[c])) )
      {
         SCIPerrorMessage("pseudo boolean linear coefficient %lf is %s\n",
               linvals[c], SCIPisFinite(linvals[c]) ? "infinite" : "nan");
         return SCIP_INVALIDDATA;
      }
   }

   for( c = 0; c < nterms; ++c )
   {
      if( ntermvars[c] == 0 && !SCIPisZero(scip, termvals[c]) )
      {
         SCIPerrorMessage("pseudo boolean term with coefficient %lf without variables\n", termvals[c]);
         return SCIP_INVALIDDATA;
      }

      if( !SCIPisFinite(termvals[c]) || SCIPisInfinity(scip, REALABS(termvals[c])) )
      {
         SCIPerrorMessage("pseudo boolean term coefficient %lf is %s\n",
               termvals[c], SCIPisFinite(termvals[c]) ? "infinite" : "nan");
         return SCIP_INVALIDDATA;
      }
   }

   /* get constraint handler data */
   conshdlrdata = SCIPconshdlrGetData(conshdlr);
   assert(conshdlrdata != NULL);

   /* initial hashmap and -table */
   SCIP_CALL( inithashmapandtable(scip, &conshdlrdata) );

   /* get temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &andconss, nterms) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andress, nterms) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andcoefs, nterms) );
   SCIP_CALL( SCIPallocBufferArray(scip, &andnegs, nterms) );

   nandconss = 0;
   /* create and-constraints */
   SCIP_CALL( createAndAddAnds(scip, conshdlr, terms, termvals, nterms, ntermvars,
         initial, enforce, check, local, modifiable, dynamic, stickingatnode,
         andconss, andcoefs, andnegs, &nandconss) );
   assert(nterms >= nandconss);

   /* get all and-resultants for linear constraint */
   for( c = nandconss - 1; c >= 0; --c )
   {
      assert(andconss[c] != NULL);
      andress[c] = SCIPgetResultantAnd(scip, andconss[c]);
   }

   linconstype = SCIP_LINEARCONSTYPE_INVALIDCONS;

   /* adjust right hand side */
   if( SCIPisInfinity(scip, rhs) )
      rhs = SCIPinfinity(scip);
   else if( SCIPisInfinity(scip, -rhs) )
      rhs = -SCIPinfinity(scip);

   /* create and add linear constraint */
   /* checking for original linear constraint will be FALSE, transformed linear constraints get the check flag like this
    * pseudoboolean constraint, in this constraint handler we only will check all and-constraints
    */
   SCIP_CALL( createAndAddLinearCons(scip, conshdlr, linvars, nlinvars, linvals, andress, nandconss, andcoefs, andnegs,
         &lhs, &rhs, issoftcons, initial, separate, enforce, FALSE/*check*/, propagate, local, modifiable, dynamic,
         removable, stickingatnode, &lincons, &linconstype) );
   assert(lincons != NULL);
   assert(linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);

   /* create constraint data */
   /* checking for and-constraints will be FALSE, we check all information in this constraint handler */
   SCIP_CALL( consdataCreate(scip, conshdlr, &consdata, lincons, linconstype, andconss, andcoefs, andnegs, nandconss,
         indvar, weight, issoftcons, lhs, rhs, check, FALSE) );
   assert(consdata != NULL);

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &andnegs);
   SCIPfreeBufferArray(scip, &andcoefs);
   SCIPfreeBufferArray(scip, &andress);
   SCIPfreeBufferArray(scip, &andconss);

   /* create constraint */
   SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
         local, modifiable, dynamic, removable, stickingatnode) );

   return SCIP_OKAY;
}

/** creates and captures a pseudoboolean constraint
 *  in its most basic variant, i. e., with all constraint flags set to their default values, which can be set
 *  afterwards using SCIPsetConsFLAGNAME() in scip.h
 *
 *  @see SCIPcreateConsPseudoboolean() for the default constraint flag configuration
 *
 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
 */
SCIP_RETCODE SCIPcreateConsBasicPseudoboolean(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
   const char*           name,               /**< name of constraint */
   SCIP_VAR**            linvars,            /**< variables of the linear part, or NULL */
   int                   nlinvars,           /**< number of variables of the linear part */
   SCIP_Real*            linvals,            /**< coefficients of linear part, or NULL */
   SCIP_VAR***           terms,              /**< nonlinear terms of variables, or NULL */
   int                   nterms,             /**< number of terms of variables of nonlinear term */
   int*                  ntermvars,          /**< number of variables in nonlinear terms, or NULL */
   SCIP_Real*            termvals,           /**< coefficients of nonlinear parts, or NULL */
   SCIP_VAR*             indvar,             /**< indicator variable if it's a soft constraint, or NULL */
   SCIP_Real             weight,             /**< weight of the soft constraint, if it is one */
   SCIP_Bool             issoftcons,         /**< is this a soft constraint */
   SCIP_Real             lhs,                /**< left hand side of constraint */
   SCIP_Real             rhs                 /**< right hand side of constraint */
   )
{
   SCIP_CALL( SCIPcreateConsPseudoboolean(scip, cons, name, linvars, nlinvars, linvals, terms, nterms, ntermvars,
         termvals, indvar, weight, issoftcons, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE,
         FALSE) );

   return SCIP_OKAY;
}

/** adds a variable to the pseudo boolean constraint (if it is not zero)
 *
 *  @note you can only add a coefficient if the special type of linear constraint won't changed
 *
 *  @todo if adding a coefficient would change the type of the special linear constraint, we need to erase it and
 *        create a new linear constraint
 */
SCIP_RETCODE SCIPaddCoefPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< constraint data */
   SCIP_VAR*const        var,                /**< variable of constraint entry */
   SCIP_Real const       val                 /**< coefficient of constraint entry */
   )
{
   SCIP_CONSDATA* consdata;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(var != NULL);

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return SCIP_INVALIDDATA; /*lint !e527*/
   }

   if( !SCIPisFinite(val) || SCIPisInfinity(scip, REALABS(val)) )
   {
      SCIPerrorMessage("pseudo boolean linear coefficient %lf is %s\n",
            val, SCIPisFinite(val) ? "infinite" : "nan");
      return SCIP_INVALIDDATA;
   }

   if( SCIPisZero(scip, val) )
      return SCIP_OKAY;

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   switch( consdata->linconstype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, var, val) );
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
      if( !SCIPisEQ(scip, val, 1.0) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefLogicor(scip, consdata->lincons, var) );
      break;
   case SCIP_LINEARCONSTYPE_KNAPSACK:
      if( !SCIPisIntegral(scip, val) || !SCIPisPositive(scip, val) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefKnapsack(scip, consdata->lincons, var, (SCIP_Longint) val) );
      break;
   case SCIP_LINEARCONSTYPE_SETPPC:
      if( !SCIPisEQ(scip, val, 1.0) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefSetppc(scip, consdata->lincons, var) );
      break;
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
      if( !SCIPisIntegral(scip, val) || !SCIPisPositive(scip, val) )
         return SCIP_INVALIDDATA;

      SCIP_CALL( SCIPaddCoefEQKnapsack(scip, consdata->lincons, var, (SCIP_Longint) val) );
      break;
#endif
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   consdata->propagated = FALSE;
   consdata->presolved = FALSE;
   consdata->cliquesadded = FALSE;

   return SCIP_OKAY;
}

/** adds nonlinear term to pseudo boolean constraint (if it is not zero)
 *
 *  @note you can only add a coefficient if the special type of linear constraint won't changed
 *
 *  @todo if adding a coefficient would change the type of the special linear constraint, we need to erase it and
 *        create a new linear constraint
 */
SCIP_RETCODE SCIPaddTermPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_VAR**const       vars,               /**< variables of the nonlinear term */
   int const             nvars,              /**< number of variables of the nonlinear term */
   SCIP_Real const       val                 /**< coefficient of constraint entry */
   )
{
   assert(scip != NULL);
   assert(cons != NULL);
   assert(vars != NULL || nvars == 0);

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return SCIP_INVALIDDATA; /*lint !e527*/
   }

   if( nvars == 0 && !SCIPisZero(scip, val) )
   {
      SCIPerrorMessage("pseudo boolean term with coefficient %lf without variables\n", val);
      return SCIP_INVALIDDATA;
   }

   if( !SCIPisFinite(val) || SCIPisInfinity(scip, REALABS(val)) )
   {
      SCIPerrorMessage("pseudo boolean term coefficient %lf is %s\n",
            val, SCIPisFinite(val) ? "infinite" : "nan");
      return SCIP_INVALIDDATA;
   }

   SCIP_CALL( addCoefTerm(scip, cons, vars, nvars, val) );

   return SCIP_OKAY;
}

/** gets indicator variable of pseudoboolean constraint, or NULL if there is no */
SCIP_VAR* SCIPgetIndVarPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< constraint data */
   )
{
   SCIP_CONSDATA* consdata;

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

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return NULL; /*lint !e527*/
   }

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   return consdata->indvar;
}

/** gets linear constraint of pseudoboolean constraint */
SCIP_CONS* SCIPgetLinearConsPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< constraint data */
   )
{
   SCIP_CONSDATA* consdata;

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

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return NULL; /*lint !e527*/
   }

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   return consdata->lincons;
}

/** gets type of linear constraint of pseudoboolean constraint */
SCIP_LINEARCONSTYPE SCIPgetLinearConsTypePseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< constraint data */
   )
{
   SCIP_CONSDATA* consdata;

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

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return SCIP_LINEARCONSTYPE_INVALIDCONS; /*lint !e527*/
   }

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   return consdata->linconstype;
}

/** gets number of linear variables without artificial terms variables of pseudoboolean constraint */
int SCIPgetNLinVarsWithoutAndPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< pseudoboolean constraint */
   )
{
   SCIP_CONSDATA* consdata;

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

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return -1;  /*lint !e527*/
   }

   checkConsConsistency(scip, cons);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   return consdata->nlinvars;
}

/** gets linear constraint of pseudoboolean constraint */
SCIP_RETCODE SCIPgetLinDatasWithoutAndPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_VAR**const       linvars,            /**< array to store and-constraints */
   SCIP_Real*const       lincoefs,           /**< array to store and-coefficients */
   int*const             nlinvars            /**< pointer to store the required array size for and-constraints, have to
                                              *   be initialized with size of given array */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_VAR** vars;
   SCIP_Real* coefs;
   int nvars;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(nlinvars != NULL);

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return SCIP_INVALIDDATA; /*lint !e527*/
   }

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   checkConsConsistency(scip, cons);

   if( *nlinvars < consdata->nlinvars )
   {
      *nlinvars = consdata->nlinvars;
      return SCIP_OKAY;
   }

   /* gets number of variables in linear constraint */
   SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );

   /* get variables and coefficient of linear constraint */
   SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );

   /* calculate all not artificial linear variables */
   SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, nlinvars, NULL, NULL, NULL, NULL) );

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &coefs);
   SCIPfreeBufferArray(scip, &vars);

   return SCIP_OKAY;
}


/** gets and-constraints of pseudoboolean constraint */
SCIP_RETCODE SCIPgetAndDatasPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< pseudoboolean constraint */
   SCIP_CONS**const      andconss,           /**< array to store and-constraints */
   SCIP_Real*const       andcoefs,           /**< array to store and-coefficients */
   int*const             nandconss           /**< pointer to store the required array size for and-constraints, have to
                                              *   be initialized with size of given array */
   )
{
   SCIP_CONSDATA* consdata;
   SCIP_Bool isorig;
   int c;

   assert(scip != NULL);
   assert(cons != NULL);
   assert(nandconss != NULL);

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return SCIP_INVALIDDATA; /*lint !e527*/
   }

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   checkConsConsistency(scip, cons);

   if( *nandconss < consdata->nconsanddatas )
   {
      *nandconss = consdata->nconsanddatas;
      return SCIP_OKAY;
   }

   *nandconss = consdata->nconsanddatas;
   assert(consdata->consanddatas != NULL || *nandconss == 0);

   isorig = SCIPconsIsOriginal(cons);

   for( c = *nandconss - 1; c >= 0; --c )
   {
      assert(consdata->consanddatas[c] != NULL);
      assert(consdata->consanddatas[c]->istransformed ? (consdata->consanddatas[c]->cons != NULL) : TRUE);
      assert(consdata->consanddatas[c]->isoriginal ? (consdata->consanddatas[c]->origcons != NULL) : TRUE);
      assert(consdata->consanddatas[c]->cons != NULL || consdata->consanddatas[c]->origcons != NULL);
      assert(isorig ? consdata->consanddatas[c]->origcons != NULL : consdata->consanddatas[c]->cons != NULL);

      andconss[c] = (isorig ? consdata->consanddatas[c]->origcons : consdata->consanddatas[c]->cons);
      assert(andconss[c] != NULL);

      andcoefs[c] = consdata->andcoefs[c];
   }

   return SCIP_OKAY;
}

/** gets number of and constraints of pseudoboolean constraint */
int SCIPgetNAndsPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< constraint data */
   )
{
   SCIP_CONSDATA* consdata;

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

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return -1;  /*lint !e527*/
   }

   checkConsConsistency(scip, cons);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   return consdata->nconsanddatas;
}

/** changes left hand side of pseudoboolean constraint
 *
 *  @note you can only change the left hand side if the special type of linear constraint won't changed
 *
 *  @todo if changing the left hand side would change the type of the special linear constraint, we need to erase it
 *        and create a new linear constraint
 */
SCIP_RETCODE SCIPchgLhsPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< constraint data */
   SCIP_Real const       lhs                 /**< new left hand side */
   )
{
   SCIP_CONSDATA* consdata;

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

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      return SCIP_INVALIDDATA;
   }

   checkConsConsistency(scip, cons);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   switch( consdata->linconstype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      SCIP_CALL( chgLhs(scip, cons, lhs) );
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
   case SCIP_LINEARCONSTYPE_KNAPSACK:
   case SCIP_LINEARCONSTYPE_SETPPC:
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
#endif
      SCIPerrorMessage("changing left hand side only allowed on standard linear constraint \n");
      return SCIP_INVALIDDATA;
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   return SCIP_OKAY;
}

/** changes right hand side of pseudoboolean constraint
 *
 *  @note you can only change the right hand side if the special type of linear constraint won't changed
 *
 *  @todo if changing the right hand side would change the type of the special linear constraint, we need to erase it
 *        and create a new linear constraint
 */
SCIP_RETCODE SCIPchgRhsPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons,               /**< constraint data */
   SCIP_Real const       rhs                 /**< new right hand side */
   )
{
   SCIP_CONSDATA* consdata;

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      return SCIP_INVALIDDATA;
   }

   checkConsConsistency(scip, cons);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   switch( consdata->linconstype )
   {
   case SCIP_LINEARCONSTYPE_LINEAR:
      SCIP_CALL( chgRhs(scip, cons, rhs) );
      break;
   case SCIP_LINEARCONSTYPE_LOGICOR:
   case SCIP_LINEARCONSTYPE_KNAPSACK:
   case SCIP_LINEARCONSTYPE_SETPPC:
#ifdef WITHEQKNAPSACK
   case SCIP_LINEARCONSTYPE_EQKNAPSACK:
#endif
      SCIPerrorMessage("changing right hand side only allowed on standard linear constraint \n");
      return SCIP_INVALIDDATA;
   case SCIP_LINEARCONSTYPE_INVALIDCONS:
   default:
      SCIPerrorMessage("unknown linear constraint type\n");
      return SCIP_INVALIDDATA;
   }

   return SCIP_OKAY;
}

/** get left hand side of pseudoboolean constraint */
SCIP_Real SCIPgetLhsPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< pseudoboolean constraint */
   )
{
   SCIP_CONSDATA* consdata;

   assert(scip != NULL);

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return SCIP_INVALID; /*lint !e527*/
   }

   checkConsConsistency(scip, cons);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   return consdata->lhs;
}

/** get right hand side of pseudoboolean constraint */
SCIP_Real SCIPgetRhsPseudoboolean(
   SCIP*const            scip,               /**< SCIP data structure */
   SCIP_CONS*const       cons                /**< pseudoboolean constraint */
   )
{
   SCIP_CONSDATA* consdata;

   assert(scip != NULL);

   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
   {
      SCIPerrorMessage("constraint is not pseudo boolean\n");
      SCIPABORT();
      return SCIP_INVALID; /*lint !e527*/
   }

   checkConsConsistency(scip, cons);

   consdata = SCIPconsGetData(cons);
   assert(consdata != NULL);

   return consdata->rhs;
}
