From f733e52c5ef3a6dc61fe1737234cc99aaa7947da Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Tue, 28 May 2024 15:52:44 +0200 Subject: [PATCH 01/14] reimplement SCIPvarGetActiveRepresentatives We use dense arrays to avoid passing over the list and repeatedly resorting. --- src/scip/scip_var.c | 2 +- src/scip/var.c | 422 +++++++++++++++++--------------------------- src/scip/var.h | 3 +- 3 files changed, 163 insertions(+), 264 deletions(-) diff --git a/src/scip/scip_var.c b/src/scip/scip_var.c index 820a5bb46b..282adbbe5c 100644 --- a/src/scip/scip_var.c +++ b/src/scip/scip_var.c @@ -1767,7 +1767,7 @@ SCIP_RETCODE SCIPgetProbvarLinearSum( assert( *nvars <= varssize ); SCIP_CALL( SCIPcheckStage(scip, "SCIPgetProbvarLinearSum", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) ); - SCIP_CALL( SCIPvarGetActiveRepresentatives(scip->set, vars, scalars, nvars, varssize, constant, requiredsize, mergemultiples) ); + SCIP_CALL( SCIPvarGetActiveRepresentatives(scip->set, vars, scalars, nvars, varssize, constant, requiredsize) ); return SCIP_OKAY; } diff --git a/src/scip/var.c b/src/scip/var.c index ec1532055a..aa739942b9 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -61,6 +61,7 @@ #include "scip/pub_prop.h" #include "scip/pub_var.h" #include "scip/relax.h" +#include "scip/scip_prob.h" #include "scip/set.h" #include "scip/sol.h" #include "scip/stat.h" @@ -3928,7 +3929,7 @@ SCIP_RETCODE SCIPvarFix( /** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant * * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except - * that the required size is stored in the corresponding variable; hence, if afterwards the required size is greater than the + * that the required size is stored in the variable requiredsize; hence, if afterwards the required size is greater than the * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays. * * The reason for this approach is that we cannot reallocate memory, since we do not know how the @@ -3941,21 +3942,18 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( int* nvars, /**< pointer to number of variables and values in vars and scalars array */ int varssize, /**< available slots in vars and scalars array */ SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ - int* requiredsize, /**< pointer to store the required array size for the active variables */ - SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */ + int* requiredsize /**< pointer to store the required array size for the active variables */ ) { SCIP_VAR** activevars; - SCIP_Real* activescalars; - int nactivevars; SCIP_Real activeconstant; SCIP_Bool activeconstantinf; int activevarssize; + int nactivevars; SCIP_VAR* var; SCIP_Real scalar; int v; - int k; SCIP_VAR** tmpvars; SCIP_VAR** multvars; @@ -3968,20 +3966,11 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( SCIP_VAR* multvar; SCIP_Real multscalar; SCIP_Real multconstant; - int pos; - - int noldtmpvars; - - SCIP_VAR** tmpvars2; - SCIP_Real* tmpscalars2; - int tmpvarssize2; - int ntmpvars2; - - SCIP_Bool sortagain = FALSE; + SCIP_Bool foundmultaggr = FALSE; + int ntotalvars; assert(set != NULL); assert(nvars != NULL); - assert(scalars != NULL || *nvars == 0); assert(constant != NULL); assert(requiredsize != NULL); assert(*nvars <= varssize); @@ -3992,6 +3981,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( return SCIP_OKAY; assert(vars != NULL); + assert(scalars != NULL); /* handle the "easy" case of just one variable and avoid memory allocation if the variable is already active */ if( *nvars == 1 && (vars[0]->varstatus == ((int) SCIP_VARSTATUS_COLUMN) || vars[0]->varstatus == ((int) SCIP_VARSTATUS_LOOSE)) ) @@ -4001,95 +3991,126 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( return SCIP_OKAY; } - nactivevars = 0; - activeconstant = 0.0; - activeconstantinf = FALSE; - activevarssize = (*nvars) * 2; - ntmpvars = *nvars; + /* allocate temporary list of variables */ + activevarssize = 2 * (*nvars); tmpvarssize = *nvars; + SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars, tmpvarssize) ); - tmpvarssize2 = 1; + /* allocate dense array for storing scalars (to avoid checking for duplicate variables) */ + ntotalvars = SCIPgetNTotalVars(set->scip); + SCIP_CALL( SCIPsetAllocCleanBufferArray(set, &tmpscalars, ntotalvars) ); - /* allocate temporary memory */ - SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars2, tmpvarssize2) ); - SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpscalars2, tmpvarssize2) ); - SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) ); - SCIP_CALL( SCIPsetAllocBufferArray(set, &activescalars, activevarssize) ); - SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpvars, vars, ntmpvars) ); - SCIP_CALL( SCIPsetDuplicateBufferArray(set, &tmpscalars, scalars, ntmpvars) ); - - /* to avoid unnecessary expanding of variable arrays while disaggregating several variables multiple times combine same variables - * first, first get all corresponding variables with status loose, column, multaggr or fixed - */ - for( v = ntmpvars - 1; v >= 0; --v ) + /* perform one round of replacing variables by their active, fixed or multi-aggregated counterparts */ + activeconstant = 0.0; + ntmpvars = 0; + for( v = 0; v < *nvars; ++v ) { - var = tmpvars[v]; - scalar = tmpscalars[v]; - + var = vars[v]; assert(var != NULL); - /* transforms given variable, scalar and constant to the corresponding active, fixed, or - * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed - * variable, "scalar" will be 0.0 and the value of the sum will be stored in "constant". - */ + scalar = scalars[v]; + + /* Transforms variable, scalar and constant to corresponding active, fixed, or multi-aggregated variable, scalar + * and constant; activeconstant collects the sum of all constants (even for variables with scalar == 0.0). */ SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &activeconstant) ); assert(var != NULL); assert(SCIPsetIsInfinity(set, activeconstant) == (activeconstant == SCIPsetInfinity(set))); /*lint !e777*/ assert(SCIPsetIsInfinity(set, -activeconstant) == (activeconstant == -SCIPsetInfinity(set))); /*lint !e777*/ - activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant); - assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); - tmpvars[v] = var; - tmpscalars[v] = scalar; + if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR ) + foundmultaggr = TRUE; + + /* enter nonzero scalars into dense array and list */ + if( scalar != 0.0 ) + { + assert(0 <= var->index && var->index < ntotalvars); + if( tmpscalars[var->index] == 0.0 ) + tmpvars[ntmpvars++] = var; + tmpscalars[var->index] += scalar; + } } - noldtmpvars = ntmpvars; + assert(ntmpvars <= *nvars); - /* sort all variables to combine equal variables easily */ - SCIPsortPtrReal((void**)tmpvars, tmpscalars, SCIPvarComp, noldtmpvars); - ntmpvars = 0; - for( v = 1; v < noldtmpvars; ++v ) + /* store whether the constant is infinite */ + activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant); + + /* if no multi-aggregated variables are left, we have resolved all dependencies and can exit a bit faster */ + if( ! foundmultaggr ) { - /* combine same variables */ - if( SCIPvarCompare(tmpvars[v], tmpvars[ntmpvars]) == 0 ) + *requiredsize = ntmpvars; + assert(*requiredsize <= varssize); + + /* sort variables for making the results consistent (todo: check whether this is necessary) */ + SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars); + + /* copy active variable and scalar array to the given arrays */ + *nvars = 0; + for( v = 0; v < ntmpvars; ++v ) { - tmpscalars[ntmpvars] += tmpscalars[v]; + var = tmpvars[v]; + assert(0 <= var->index && var->index < ntotalvars); + + if( tmpscalars[var->index] != 0.0 ) + { + vars[*nvars] = var; + scalars[*nvars] = tmpscalars[var->index]; + assert(scalars[*nvars] != 0.0); + + /* ensure that dense array is zero at end */ + tmpscalars[var->index] = 0.0; + ++(*nvars); + } } + + if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) ) + { + /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */ + if( activeconstantinf ) + *constant = activeconstant; + else + *constant += activeconstant; + } +#ifndef NDEBUG else { - ++ntmpvars; - if( v > ntmpvars ) - { - tmpscalars[ntmpvars] = tmpscalars[v]; - tmpvars[ntmpvars] = tmpvars[v]; - } + assert(!SCIPsetIsInfinity(set, (*constant)) || !SCIPsetIsInfinity(set, -activeconstant)); + assert(!SCIPsetIsInfinity(set, -(*constant)) || !SCIPsetIsInfinity(set, activeconstant)); } +#endif + + SCIPsetFreeCleanBufferArray(set, &tmpscalars); + SCIPsetFreeBufferArray(set, &tmpvars); + + return SCIP_OKAY; } - ++ntmpvars; -#ifdef SCIP_MORE_DEBUG - for( v = 1; v < ntmpvars; ++v ) - assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0); -#endif + /* allocate memory for list of active variables */ + nactivevars = 0; + SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) ); /* collect for each variable the representation in active variables */ while( ntmpvars >= 1 ) { --ntmpvars; - ntmpvars2 = 0; - var = tmpvars[ntmpvars]; - scalar = tmpscalars[ntmpvars]; + var = tmpvars[ntmpvars]; assert(var != NULL); + assert(0 <= var->index && var->index < ntotalvars); - /* TODO: maybe we should test here on SCIPsetIsZero() instead of 0.0 */ - if( scalar == 0.0 ) + scalar = tmpscalars[var->index]; + /* the scalar can be 0 if the variable has been treated before and is zeroed below */ + if(scalar == 0.0) continue; + /* mark variable as treated */ + tmpscalars[var->index] = 0.0; + + /* because of the initial round above, only the following types are allowed at this point: */ assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR @@ -4099,17 +4120,21 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( { case SCIP_VARSTATUS_LOOSE: case SCIP_VARSTATUS_COLUMN: - /* x = a*y + c */ - if( nactivevars >= activevarssize ) + + /* store the variable in list if not already active */ + if( tmpscalars[var->index] == 0.0 ) { - activevarssize *= 2; - SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) ); - SCIP_CALL( SCIPsetReallocBufferArray(set, &activescalars, activevarssize) ); - assert(nactivevars < activevarssize); + if( nactivevars >= activevarssize ) + { + activevarssize *= 2; + SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) ); + assert(nactivevars < activevarssize); + } + activevars[nactivevars++] = var; } - activevars[nactivevars] = var; - activescalars[nactivevars] = scalar; - nactivevars++; + + /* store scalar to dense array */ + tmpscalars[var->index] += scalar; break; case SCIP_VARSTATUS_MULTAGGR: @@ -4117,43 +4142,28 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( nmultvars = var->data.multaggr.nvars; multvars = var->data.multaggr.vars; multscalars = var->data.multaggr.scalars; - sortagain = TRUE; + /* reallocate space here instead of possibly reallocating several times below */ if( nmultvars + ntmpvars > tmpvarssize ) { while( nmultvars + ntmpvars > tmpvarssize ) tmpvarssize *= 2; SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) ); - SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars, tmpvarssize) ); assert(nmultvars + ntmpvars <= tmpvarssize); } - if( nmultvars > tmpvarssize2 ) - { - while( nmultvars > tmpvarssize2 ) - tmpvarssize2 *= 2; - SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars2, tmpvarssize2) ); - SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpscalars2, tmpvarssize2) ); - assert(nmultvars <= tmpvarssize2); - } - - --nmultvars; - - for( ; nmultvars >= 0; --nmultvars ) + /* loop through variables of multi-aggregation */ + for( v = 0; v < nmultvars; ++v ) { - multvar = multvars[nmultvars]; - multscalar = multscalars[nmultvars]; - multconstant = 0; + multvar = multvars[v]; + multscalar = multscalars[v]; + multconstant = 0.0; assert(multvar != NULL); SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) ); assert(multvar != NULL); - assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); - + /* handle constant */ if( !activeconstantinf ) { assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar)); @@ -4185,101 +4195,21 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( } #endif - if( SCIPsortedvecFindPtr((void**)tmpvars, SCIPvarComp, multvar, ntmpvars, &pos) ) - { - assert(SCIPvarCompare(tmpvars[pos], multvar) == 0); - tmpscalars[pos] += scalar * multscalar; - } - else - { - tmpvars2[ntmpvars2] = multvar; - tmpscalars2[ntmpvars2] = scalar * multscalar; - ++(ntmpvars2); - assert(ntmpvars2 <= tmpvarssize2); - } - } + /* Note that the variable can have a nonzero constant but 0 scalar. */ + if( multscalar == 0.0 ) + continue; - if( ntmpvars2 > 0 ) - { - /* sort all variables to combine equal variables easily */ - SCIPsortPtrReal((void**)tmpvars2, tmpscalars2, SCIPvarComp, ntmpvars2); - pos = 0; - for( v = 1; v < ntmpvars2; ++v ) - { - /* combine same variables */ - if( SCIPvarCompare(tmpvars2[v], tmpvars2[pos]) == 0 ) - { - tmpscalars2[pos] += tmpscalars2[v]; - } - else - { - ++pos; - if( v > pos ) - { - tmpscalars2[pos] = tmpscalars2[v]; - tmpvars2[pos] = tmpvars2[v]; - } - } - } - ntmpvars2 = pos + 1; -#ifdef SCIP_MORE_DEBUG - for( v = 1; v < ntmpvars2; ++v ) - { - assert(SCIPvarCompare(tmpvars2[v], tmpvars2[v-1]) > 0); - } - for( v = 1; v < ntmpvars; ++v ) - { - assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0); - } -#endif - v = ntmpvars - 1; - k = ntmpvars2 - 1; - pos = ntmpvars + ntmpvars2 - 1; - ntmpvars += ntmpvars2; + /* enter variable into list if not already present */ + assert(0 <= multvar->index && multvar->index < ntotalvars); + if( tmpscalars[multvar->index] == 0.0 ) + tmpvars[ntmpvars++] = multvar; - while( v >= 0 && k >= 0 ) - { - assert(pos >= 0); - assert(SCIPvarCompare(tmpvars[v], tmpvars2[k]) != 0); - if( SCIPvarCompare(tmpvars[v], tmpvars2[k]) >= 0 ) - { - tmpvars[pos] = tmpvars[v]; - tmpscalars[pos] = tmpscalars[v]; - --v; - } - else - { - tmpvars[pos] = tmpvars2[k]; - tmpscalars[pos] = tmpscalars2[k]; - --k; - } - --pos; - assert(pos >= 0); - } - while( v >= 0 ) - { - assert(pos >= 0); - tmpvars[pos] = tmpvars[v]; - tmpscalars[pos] = tmpscalars[v]; - --v; - --pos; - } - while( k >= 0 ) - { - assert(pos >= 0); - tmpvars[pos] = tmpvars2[k]; - tmpscalars[pos] = tmpscalars2[k]; - --k; - --pos; - } - } -#ifdef SCIP_MORE_DEBUG - for( v = 1; v < ntmpvars; ++v ) - { - assert(SCIPvarCompare(tmpvars[v], tmpvars[v-1]) > 0); + /* transfer new scalar to dense array */ + tmpscalars[multvar->index] += scalar * multscalar; + assert(scalar * multscalar != 0.0); } -#endif + /* handle constant of multi-aggregation */ if( !activeconstantinf ) { assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar)); @@ -4328,62 +4258,8 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( } } - if( mergemultiples ) - { - if( sortagain ) - { - /* sort variable and scalar array by variable index */ - SCIPsortPtrReal((void**)activevars, activescalars, SCIPvarComp, nactivevars); - - /* eliminate duplicates and count required size */ - v = nactivevars - 1; - while( v > 0 ) - { - /* combine both variable since they are the same */ - if( SCIPvarCompare(activevars[v - 1], activevars[v]) == 0 ) - { - if( activescalars[v - 1] + activescalars[v] != 0.0 ) - { - activescalars[v - 1] += activescalars[v]; - --nactivevars; - activevars[v] = activevars[nactivevars]; - activescalars[v] = activescalars[nactivevars]; - } - else - { - --nactivevars; - activevars[v] = activevars[nactivevars]; - activescalars[v] = activescalars[nactivevars]; - --nactivevars; - --v; - activevars[v] = activevars[nactivevars]; - activescalars[v] = activescalars[nactivevars]; - } - } - --v; - } - } - /* the variables were added in reverse order, we revert the order now; - * this should not be necessary, but not doing this changes the behavior sometimes - */ - else - { - SCIP_VAR* tmpvar; - SCIP_Real tmpscalar; - - for( v = 0; v < nactivevars / 2; ++v ) - { - tmpvar = activevars[v]; - tmpscalar = activescalars[v]; - activevars[v] = activevars[nactivevars - 1 - v]; - activescalars[v] = activescalars[nactivevars - 1 - v]; - activevars[nactivevars - 1 - v] = tmpvar; - activescalars[nactivevars - 1 - v] = tmpscalar; - } - } - } + /* return results */ *requiredsize = nactivevars; - if( varssize >= *requiredsize ) { assert(vars != NULL); @@ -4394,9 +4270,9 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( { /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */ if( activeconstantinf ) - (*constant) = activeconstant; + *constant = activeconstant; else - (*constant) += activeconstant; + *constant += activeconstant; } #ifndef NDEBUG else @@ -4406,23 +4282,46 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( } #endif + /* sort active variables for making the results consistent (todo: check whether this is necessary) */ + SCIPsortPtr((void**)activevars, SCIPvarComp, nactivevars); + /* copy active variable and scalar array to the given arrays */ - for( v = 0; v < *nvars; ++v ) + *nvars = 0; + for( v = 0; v < nactivevars; ++v ) + { + var = activevars[v]; + + assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); + assert(0 <= var->index && var->index < ntotalvars); + if( tmpscalars[var->index] != 0.0 ) + { + vars[*nvars] = var; + scalars[*nvars] = tmpscalars[var->index]; + assert(scalars[*nvars] != 0.0); + ++(*nvars); + } + + /* clean buffer again */ + tmpscalars[var->index] = 0.0; + } + } + else + { + /* clean buffer again */ + for( v = 0; v < nactivevars; ++v ) { - vars[v] = activevars[v]; - scalars[v] = activescalars[v]; /*lint !e613*/ + var = activevars[v]; + assert( 0 <= var->index && var->index < ntotalvars ); + tmpscalars[var->index] = 0.0; } } assert(SCIPsetIsInfinity(set, *constant) == ((*constant) == SCIPsetInfinity(set))); /*lint !e777*/ assert(SCIPsetIsInfinity(set, -(*constant)) == ((*constant) == -SCIPsetInfinity(set))); /*lint !e777*/ - SCIPsetFreeBufferArray(set, &tmpscalars); - SCIPsetFreeBufferArray(set, &tmpvars); - SCIPsetFreeBufferArray(set, &activescalars); SCIPsetFreeBufferArray(set, &activevars); - SCIPsetFreeBufferArray(set, &tmpscalars2); - SCIPsetFreeBufferArray(set, &tmpvars2); + SCIPsetFreeCleanBufferArray(set, &tmpscalars); + SCIPsetFreeBufferArray(set, &tmpvars); return SCIP_OKAY; } @@ -4480,16 +4379,17 @@ SCIP_RETCODE SCIPvarFlattenAggregationGraph( nmultvars = var->data.multaggr.nvars; multvarssize = var->data.multaggr.varssize; - SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) ); + SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize) ); if( multrequiredsize > multvarssize ) { SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.vars), multvarssize, multrequiredsize) ); SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(var->data.multaggr.scalars), multvarssize, multrequiredsize) ); multvarssize = multrequiredsize; - SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize, TRUE) ); + SCIP_CALL( SCIPvarGetActiveRepresentatives(set, var->data.multaggr.vars, var->data.multaggr.scalars, &nmultvars, multvarssize, &multconstant, &multrequiredsize) ); assert( multrequiredsize <= multvarssize ); } + /**@note After the flattening the multi aggregation might resolve to be in fact an aggregation (or even a fixing?). * This issue is not resolved right now, since var->data.multaggr.nvars < 2 should not cause troubles. However, one * may loose performance hereby, since aggregated variables are easier to handle. @@ -5527,13 +5427,13 @@ SCIP_RETCODE SCIPvarMultiaggregate( SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &tmpscalars, scalars, ntmpvars) ); /* get all active variables for multi-aggregation */ - SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) ); + SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize) ); if( tmprequiredsize > tmpvarssize ) { SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpvars, tmpvarssize, tmprequiredsize) ); SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tmpscalars, tmpvarssize, tmprequiredsize) ); tmpvarssize = tmprequiredsize; - SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize, FALSE) ); + SCIP_CALL( SCIPvarGetActiveRepresentatives(set, tmpvars, tmpscalars, &ntmpvars, tmpvarssize, &tmpconstant, &tmprequiredsize) ); assert( tmprequiredsize <= tmpvarssize ); } diff --git a/src/scip/var.h b/src/scip/var.h index eae4a16a9d..cfaf78c99f 100644 --- a/src/scip/var.h +++ b/src/scip/var.h @@ -417,8 +417,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( int* nvars, /**< pointer to number of variables and values in vars and vals array */ int varssize, /**< available slots in vars and scalars array */ SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ - int* requiredsize, /**< pointer to store the required array size for the active variables */ - SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */ + int* requiredsize /**< pointer to store the required array size for the active variables */ ); /** transforms given variable, scalar and constant to the corresponding active, fixed, or From b6a2fa60c766a64c4012eccb56947cda01048a2c Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Tue, 28 May 2024 16:11:11 +0200 Subject: [PATCH 02/14] remove parameter mergemultiples --- CHANGELOG | 4 ++++ src/scip/cons_countsols.c | 2 +- src/scip/cons_linear.c | 12 ++++++------ src/scip/cons_logicor.c | 8 ++++---- src/scip/cons_pseudoboolean.c | 4 ++-- src/scip/cons_setppc.c | 8 ++++---- src/scip/cons_sos1.c | 4 ++-- src/scip/expr_var.c | 4 ++-- src/scip/matrix.c | 4 ++-- src/scip/prop_genvbounds.c | 4 ++-- src/scip/reader_ccg.c | 4 ++-- src/scip/reader_fzn.c | 4 ++-- src/scip/reader_gms.c | 4 ++-- src/scip/reader_lp.c | 4 ++-- src/scip/reader_mps.c | 4 ++-- src/scip/reader_opb.c | 4 ++-- src/scip/reader_pbm.c | 4 ++-- src/scip/reader_pip.c | 4 ++-- src/scip/reader_ppm.c | 4 ++-- src/scip/scip_var.c | 3 +-- src/scip/scip_var.h | 3 +-- src/scip/sol.c | 2 +- src/scip/symmetry_graph.c | 4 ++-- 23 files changed, 52 insertions(+), 50 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a36f18809f..ad97144df6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ Features Performance improvements ------------------------ +- Reimplemented SCIPvarGetActiveRepresentatives() by using dense arrays to avoid repeated resorting. + Examples and applications ------------------------- @@ -21,6 +23,8 @@ Interface changes ### Deleted and changed API methods +- SCIPgetProbvarLinearSum: remove parameter mergemultiples, which is now automatically true with the new implementation of SCIPvarGetActiveRepresentatives. + ### New API functions - SCIPhistoryUpdateAncPseudocost(), SCIPvarUpdateAncPseudocost() for updating the ancestral pseudo cost fields in variable history diff --git a/src/scip/cons_countsols.c b/src/scip/cons_countsols.c index 189024b82b..658727902f 100644 --- a/src/scip/cons_countsols.c +++ b/src/scip/cons_countsols.c @@ -2237,7 +2237,7 @@ SCIP_RETCODE writeExpandedSolutions( nvars = 1; constant = 0.0; - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, &nvars, nallvars, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, &nvars, nallvars, &constant, &requiredsize) ); assert(requiredsize <= nallvars); assert(nvars <= nactivevars); diff --git a/src/scip/cons_linear.c b/src/scip/cons_linear.c index 0e9d33db63..1a5def4d26 100644 --- a/src/scip/cons_linear.c +++ b/src/scip/cons_linear.c @@ -18005,7 +18005,7 @@ SCIP_RETCODE SCIPcreateConsLinear( SCIP_CALL( SCIPduplicateBufferArray(scip, &consvals, vals, nconsvars) ); /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize) ); /* if space was not enough we need to resize the buffers */ if( requiredsize > nconsvars ) @@ -18013,7 +18013,7 @@ SCIP_RETCODE SCIPcreateConsLinear( SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); assert(requiredsize <= nconsvars); } @@ -18224,14 +18224,14 @@ SCIP_RETCODE SCIPcopyConsLinear( */ if( !SCIPvarIsOriginal(vars[0]) ) { - SCIP_CALL( SCIPgetProbvarLinearSum(sourcescip, vars, coefs, &nvars, nvars, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(sourcescip, vars, coefs, &nvars, nvars, &constant, &requiredsize) ); if( requiredsize > nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(sourcescip, vars, coefs, &nvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(sourcescip, vars, coefs, &nvars, requiredsize, &constant, &requiredsize) ); assert(requiredsize <= nvars); } } @@ -18321,7 +18321,7 @@ SCIP_RETCODE SCIPaddCoefLinear( consvals[0] = val; /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize) ); /* if space was not enough we need to resize the buffers */ if( requiredsize > nconsvars ) @@ -18329,7 +18329,7 @@ SCIP_RETCODE SCIPaddCoefLinear( SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); assert(requiredsize <= nconsvars); } diff --git a/src/scip/cons_logicor.c b/src/scip/cons_logicor.c index 3cc0e3c1d1..1b2b74669d 100644 --- a/src/scip/cons_logicor.c +++ b/src/scip/cons_logicor.c @@ -1004,14 +1004,14 @@ SCIP_RETCODE applyFixings( consvals[0] = 1.0; /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize) ); /* if space was not enough we need to resize the buffers */ if( requiredsize > nconsvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); assert(requiredsize <= nconsvars); } @@ -1080,7 +1080,7 @@ SCIP_RETCODE applyFixings( constant = 0.0; /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); /* if space was not enough(we found another multi-aggregation), we need to resize the buffers */ if( requiredsize > nconsvars ) @@ -1088,7 +1088,7 @@ SCIP_RETCODE applyFixings( SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); assert(requiredsize <= nconsvars); } diff --git a/src/scip/cons_pseudoboolean.c b/src/scip/cons_pseudoboolean.c index 9c332d1239..32dd921588 100644 --- a/src/scip/cons_pseudoboolean.c +++ b/src/scip/cons_pseudoboolean.c @@ -5256,7 +5256,7 @@ SCIP_RETCODE correctConshdlrdata( nactivevars = 1; SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activescalars, &nactivevars, SCIPgetNVars(scip), - &activeconstant, &requiredsize, TRUE) ); + &activeconstant, &requiredsize) ); assert(requiredsize <= SCIPgetNVars(scip)); if( nactivevars == 0 ) @@ -5863,7 +5863,7 @@ SCIP_RETCODE tryUpgradingXor( constant = 0; /* get linear active representation */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, linvars, lincoefs, &nlinvars, MAXNVARS, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, linvars, lincoefs, &nlinvars, MAXNVARS, &constant, &requiredsize) ); SCIP_CALL( SCIPduplicateBufferArray(scip, &activelinvars, linvars, nlinvars) ); if( requiredsize > MAXNVARS ) diff --git a/src/scip/cons_setppc.c b/src/scip/cons_setppc.c index 96a087bc20..69ee2731c4 100644 --- a/src/scip/cons_setppc.c +++ b/src/scip/cons_setppc.c @@ -1840,14 +1840,14 @@ SCIP_RETCODE applyFixings( consvals[0] = 1.0; /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize) ); /* if space was not enough we need to resize the buffers */ if( requiredsize > nconsvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); assert(requiredsize <= nconsvars); } @@ -1975,7 +1975,7 @@ SCIP_RETCODE applyFixings( constant = 0.0; /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); /* if space was not enough (we found another multi-aggregation), we need to resize the buffers */ if( requiredsize > nconsvars ) @@ -1983,7 +1983,7 @@ SCIP_RETCODE applyFixings( SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); assert(requiredsize <= nconsvars); } diff --git a/src/scip/cons_sos1.c b/src/scip/cons_sos1.c index 765e88b9e8..d836cf95f2 100644 --- a/src/scip/cons_sos1.c +++ b/src/scip/cons_sos1.c @@ -2805,13 +2805,13 @@ SCIP_RETCODE tightenVarsBoundsSOS1( /* transform linear constraint */ constant = 0.0; - SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, ntrafolinvars, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, ntrafolinvars, &constant, &requiredsize) ); if( requiredsize > ntrafolinvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvars, requiredsize + 1) ); SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvals, requiredsize + 1) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, requiredsize, &constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, requiredsize, &constant, &requiredsize) ); assert( requiredsize <= ntrafolinvars ); } if( !SCIPisInfinity(scip, -trafolhs) ) diff --git a/src/scip/expr_var.c b/src/scip/expr_var.c index 8f5c877f16..388121daea 100644 --- a/src/scip/expr_var.c +++ b/src/scip/expr_var.c @@ -104,14 +104,14 @@ SCIP_DECL_EXPRSIMPLIFY(simplifyVar) { int requsize; - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize) ); if( requsize > varssize ) { SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, requsize) ); varssize = requsize; - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize) ); assert(requsize <= nvars); } } diff --git a/src/scip/matrix.c b/src/scip/matrix.c index a9d1080e09..6b4e4cacf0 100644 --- a/src/scip/matrix.c +++ b/src/scip/matrix.c @@ -82,7 +82,7 @@ SCIP_RETCODE getActiveVariables( assert(nvars != NULL); assert(constant != NULL); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { @@ -90,7 +90,7 @@ SCIP_RETCODE getActiveVariables( SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) ); /* call function a second time with enough memory */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize) ); assert(requiredsize <= *nvars); } diff --git a/src/scip/prop_genvbounds.c b/src/scip/prop_genvbounds.c index db3dc7ed4a..d521a055fe 100644 --- a/src/scip/prop_genvbounds.c +++ b/src/scip/prop_genvbounds.c @@ -2480,7 +2480,7 @@ SCIP_DECL_PROPEXITPRE(propExitpreGenvbounds) /* replace non-active by active variables and update constant; note that this may result in coefficients where * SCIPisZero() is true; this should not create any problems */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, genvbound->ncoefs, &genvbound->constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, genvbound->ncoefs, &genvbound->constant, &requiredsize) ); /* if space was not enough we need to resize the buffers */ if( requiredsize > genvbound->ncoefs ) @@ -2493,7 +2493,7 @@ SCIP_DECL_PROPEXITPRE(propExitpreGenvbounds) genvbound->coefssize = requiredsize; } - SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, requiredsize, &genvbound->constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, genvbound->vars, genvbound->coefs, &genvbound->ncoefs, requiredsize, &genvbound->constant, &requiredsize) ); assert(requiredsize <= genvbound->ncoefs); } diff --git a/src/scip/reader_ccg.c b/src/scip/reader_ccg.c index ab80ab4f9f..aa7c5813bd 100644 --- a/src/scip/reader_ccg.c +++ b/src/scip/reader_ccg.c @@ -184,14 +184,14 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize) ); assert( requiredsize <= *nvars ); } } diff --git a/src/scip/reader_fzn.c b/src/scip/reader_fzn.c index 2dcfdc97dd..cbf713fc23 100644 --- a/src/scip/reader_fzn.c +++ b/src/scip/reader_fzn.c @@ -3883,14 +3883,14 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize) ); assert( requiredsize <= *nvars ); } } diff --git a/src/scip/reader_gms.c b/src/scip/reader_gms.c index c9b56a56eb..72f358505e 100644 --- a/src/scip/reader_gms.c +++ b/src/scip/reader_gms.c @@ -107,7 +107,7 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize) ); if( requiredsize > *varssize ) { @@ -115,7 +115,7 @@ SCIP_RETCODE getActiveVariables( SCIP_CALL( SCIPreallocBufferArray(scip, vars, *varssize) ); SCIP_CALL( SCIPreallocBufferArray(scip, scalars, *varssize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *varssize, constant, &requiredsize) ); assert(requiredsize <= *varssize); } } diff --git a/src/scip/reader_lp.c b/src/scip/reader_lp.c index de3895e472..6c4b42e29c 100644 --- a/src/scip/reader_lp.c +++ b/src/scip/reader_lp.c @@ -2541,14 +2541,14 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize) ); assert( requiredsize <= *nvars ); } } diff --git a/src/scip/reader_mps.c b/src/scip/reader_mps.c index 0c0b1114a0..08d50af467 100644 --- a/src/scip/reader_mps.c +++ b/src/scip/reader_mps.c @@ -2961,14 +2961,14 @@ SCIP_RETCODE getLinearCoeffs( /* retransform given variables to active variables */ if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activevals, &nactivevars, nactivevars, &activeconstant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activevals, &nactivevars, nactivevars, &activeconstant, &requiredsize) ); if( requiredsize > nactivevars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &activevars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &activevals, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activevals, &nactivevars, requiredsize, &activeconstant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activevals, &nactivevars, requiredsize, &activeconstant, &requiredsize) ); assert( requiredsize <= nactivevars ); } } diff --git a/src/scip/reader_opb.c b/src/scip/reader_opb.c index 2f1de12307..d5c9ce0f91 100644 --- a/src/scip/reader_opb.c +++ b/src/scip/reader_opb.c @@ -1886,14 +1886,14 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize) ); assert( requiredsize <= *nvars ); } } diff --git a/src/scip/reader_pbm.c b/src/scip/reader_pbm.c index ca58607378..2aa0d3b8cb 100644 --- a/src/scip/reader_pbm.c +++ b/src/scip/reader_pbm.c @@ -96,14 +96,14 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize) ); assert(requiredsize <= *nvars); } } diff --git a/src/scip/reader_pip.c b/src/scip/reader_pip.c index 093116edd3..745bda6d78 100644 --- a/src/scip/reader_pip.c +++ b/src/scip/reader_pip.c @@ -1761,14 +1761,14 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize) ); assert( requiredsize <= *nvars ); } } diff --git a/src/scip/reader_ppm.c b/src/scip/reader_ppm.c index 22d5f2f0d0..f0890a5008 100644 --- a/src/scip/reader_ppm.c +++ b/src/scip/reader_ppm.c @@ -115,14 +115,14 @@ SCIP_RETCODE getActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize) ); assert( requiredsize <= *nvars ); } } diff --git a/src/scip/scip_var.c b/src/scip/scip_var.c index 282adbbe5c..0a35543317 100644 --- a/src/scip/scip_var.c +++ b/src/scip/scip_var.c @@ -1753,9 +1753,8 @@ SCIP_RETCODE SCIPgetProbvarLinearSum( SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c which * will chnage to constant d in the linear sum b_1*y_1 + ... + b_m*y_m + * d w.r.t. the active variables */ - int* requiredsize, /**< pointer to store the required array size for the linear sum w.r.t. the + int* requiredsize /**< pointer to store the required array size for the linear sum w.r.t. the * active variables */ - SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */ ) { assert( scip != NULL ); diff --git a/src/scip/scip_var.h b/src/scip/scip_var.h index f7912fbdda..d8bd4114c8 100644 --- a/src/scip/scip_var.h +++ b/src/scip/scip_var.h @@ -816,9 +816,8 @@ SCIP_RETCODE SCIPgetProbvarLinearSum( SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c which * will chnage to constant d in the linear sum b_1*y_1 + ... + b_m*y_m + * d w.r.t. the active variables */ - int* requiredsize, /**< pointer to store the required array size for the linear sum w.r.t. the + int* requiredsize /**< pointer to store the required array size for the linear sum w.r.t. the * active variables */ - SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */ ); /** transforms given variable, scalar and constant to the corresponding active, fixed, or diff --git a/src/scip/sol.c b/src/scip/sol.c index 9a42754d6c..799220b962 100644 --- a/src/scip/sol.c +++ b/src/scip/sol.c @@ -2126,7 +2126,7 @@ SCIP_RETCODE SCIPsolRetransform( /* get active representation of the original variable */ SCIP_CALL( SCIPvarGetActiveRepresentatives(set, activevars, activevals, &nactivevars, ntransvars + 1, &constant, - &requiredsize, TRUE) ); + &requiredsize) ); assert(requiredsize <= ntransvars); /* compute solution value of the original variable */ diff --git a/src/scip/symmetry_graph.c b/src/scip/symmetry_graph.c index daf047d18b..e1d14ae638 100644 --- a/src/scip/symmetry_graph.c +++ b/src/scip/symmetry_graph.c @@ -1719,14 +1719,14 @@ SCIP_RETCODE SCIPgetSymActiveVariables( if( transformed ) { - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize) ); if( requiredsize > *nvars ) { SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize) ); assert(requiredsize <= *nvars); } } From 411be9250a3d8837fd339a5aeb77ab63f134195b Mon Sep 17 00:00:00 2001 From: Christopher Hojny Date: Wed, 29 May 2024 10:40:57 +0200 Subject: [PATCH 03/14] Apply 1 suggestion(s) to 1 file(s) --- src/scip/var.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scip/var.c b/src/scip/var.c index aa739942b9..abcd488cdb 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -4104,7 +4104,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( scalar = tmpscalars[var->index]; /* the scalar can be 0 if the variable has been treated before and is zeroed below */ - if(scalar == 0.0) + if( scalar == 0.0 ) continue; /* mark variable as treated */ From 649eeaeba4a3548b0ea22fc879b4bd1bcbd4a5a5 Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Thu, 30 May 2024 12:51:46 +0200 Subject: [PATCH 04/14] restructure: directly collect active variables --- src/scip/var.c | 283 ++++++++++++++++++------------------------------- 1 file changed, 106 insertions(+), 177 deletions(-) diff --git a/src/scip/var.c b/src/scip/var.c index abcd488cdb..ca7f6edf2e 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -3966,7 +3966,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( SCIP_VAR* multvar; SCIP_Real multscalar; SCIP_Real multconstant; - SCIP_Bool foundmultaggr = FALSE; + SCIP_VARSTATUS varstatus; int ntotalvars; assert(set != NULL); @@ -3992,16 +3992,20 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( } /* allocate temporary list of variables */ - activevarssize = 2 * (*nvars); tmpvarssize = *nvars; SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars, tmpvarssize) ); + /* allocate memory for list of active variables */ + activevarssize = 2 * (*nvars); + SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) ); + /* allocate dense array for storing scalars (to avoid checking for duplicate variables) */ ntotalvars = SCIPgetNTotalVars(set->scip); SCIP_CALL( SCIPsetAllocCleanBufferArray(set, &tmpscalars, ntotalvars) ); /* perform one round of replacing variables by their active, fixed or multi-aggregated counterparts */ activeconstant = 0.0; + nactivevars = 0; ntmpvars = 0; for( v = 0; v < *nvars; ++v ) { @@ -4017,82 +4021,30 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( assert(SCIPsetIsInfinity(set, activeconstant) == (activeconstant == SCIPsetInfinity(set))); /*lint !e777*/ assert(SCIPsetIsInfinity(set, -activeconstant) == (activeconstant == -SCIPsetInfinity(set))); /*lint !e777*/ - assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); - - if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR ) - foundmultaggr = TRUE; + varstatus = SCIPvarGetStatus(var); + assert( varstatus == SCIP_VARSTATUS_LOOSE || varstatus == SCIP_VARSTATUS_COLUMN + || varstatus == SCIP_VARSTATUS_MULTAGGR || varstatus == SCIP_VARSTATUS_FIXED); /* enter nonzero scalars into dense array and list */ if( scalar != 0.0 ) { assert(0 <= var->index && var->index < ntotalvars); if( tmpscalars[var->index] == 0.0 ) - tmpvars[ntmpvars++] = var; + { + if( varstatus == SCIP_VARSTATUS_LOOSE || varstatus == SCIP_VARSTATUS_COLUMN ) + activevars[nactivevars++] = var; /* store active variables */ + else if( varstatus == SCIP_VARSTATUS_MULTAGGR ) + tmpvars[ntmpvars++] = var; /* enter mutli-aggregated variables in list to be processed below */ + } tmpscalars[var->index] += scalar; } } assert(ntmpvars <= *nvars); + assert(nactivevars <= *nvars); /* store whether the constant is infinite */ activeconstantinf = SCIPsetIsInfinity(set, activeconstant) || SCIPsetIsInfinity(set, -activeconstant); - /* if no multi-aggregated variables are left, we have resolved all dependencies and can exit a bit faster */ - if( ! foundmultaggr ) - { - *requiredsize = ntmpvars; - assert(*requiredsize <= varssize); - - /* sort variables for making the results consistent (todo: check whether this is necessary) */ - SCIPsortPtr((void**)tmpvars, SCIPvarComp, ntmpvars); - - /* copy active variable and scalar array to the given arrays */ - *nvars = 0; - for( v = 0; v < ntmpvars; ++v ) - { - var = tmpvars[v]; - assert(0 <= var->index && var->index < ntotalvars); - - if( tmpscalars[var->index] != 0.0 ) - { - vars[*nvars] = var; - scalars[*nvars] = tmpscalars[var->index]; - assert(scalars[*nvars] != 0.0); - - /* ensure that dense array is zero at end */ - tmpscalars[var->index] = 0.0; - ++(*nvars); - } - } - - if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) ) - { - /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */ - if( activeconstantinf ) - *constant = activeconstant; - else - *constant += activeconstant; - } -#ifndef NDEBUG - else - { - assert(!SCIPsetIsInfinity(set, (*constant)) || !SCIPsetIsInfinity(set, -activeconstant)); - assert(!SCIPsetIsInfinity(set, -(*constant)) || !SCIPsetIsInfinity(set, activeconstant)); - } -#endif - - SCIPsetFreeCleanBufferArray(set, &tmpscalars); - SCIPsetFreeBufferArray(set, &tmpvars); - - return SCIP_OKAY; - } - - /* allocate memory for list of active variables */ - nactivevars = 0; - SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) ); - /* collect for each variable the representation in active variables */ while( ntmpvars >= 1 ) { @@ -4101,121 +4053,37 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( var = tmpvars[ntmpvars]; assert(var != NULL); assert(0 <= var->index && var->index < ntotalvars); + assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR); scalar = tmpscalars[var->index]; /* the scalar can be 0 if the variable has been treated before and is zeroed below */ if( scalar == 0.0 ) continue; + /* x = a_1*y_1 + ... + a_n*y_n + c */ + nmultvars = var->data.multaggr.nvars; + multvars = var->data.multaggr.vars; + multscalars = var->data.multaggr.scalars; + /* mark variable as treated */ tmpscalars[var->index] = 0.0; - /* because of the initial round above, only the following types are allowed at this point: */ - assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR - || SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); - - switch( SCIPvarGetStatus(var) ) + /* loop through variables of multi-aggregation */ + for( v = 0; v < nmultvars; ++v ) { - case SCIP_VARSTATUS_LOOSE: - case SCIP_VARSTATUS_COLUMN: - - /* store the variable in list if not already active */ - if( tmpscalars[var->index] == 0.0 ) - { - if( nactivevars >= activevarssize ) - { - activevarssize *= 2; - SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) ); - assert(nactivevars < activevarssize); - } - activevars[nactivevars++] = var; - } - - /* store scalar to dense array */ - tmpscalars[var->index] += scalar; - break; - - case SCIP_VARSTATUS_MULTAGGR: - /* x = a_1*y_1 + ... + a_n*y_n + c */ - nmultvars = var->data.multaggr.nvars; - multvars = var->data.multaggr.vars; - multscalars = var->data.multaggr.scalars; - - /* reallocate space here instead of possibly reallocating several times below */ - if( nmultvars + ntmpvars > tmpvarssize ) - { - while( nmultvars + ntmpvars > tmpvarssize ) - tmpvarssize *= 2; - SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) ); - assert(nmultvars + ntmpvars <= tmpvarssize); - } + multvar = multvars[v]; + multscalar = multscalars[v]; + multconstant = 0.0; - /* loop through variables of multi-aggregation */ - for( v = 0; v < nmultvars; ++v ) - { - multvar = multvars[v]; - multscalar = multscalars[v]; - multconstant = 0.0; + assert(multvar != NULL); + SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) ); + assert(multvar != NULL); - assert(multvar != NULL); - SCIP_CALL( SCIPvarGetProbvarSum(&multvar, set, &multscalar, &multconstant) ); - assert(multvar != NULL); - - /* handle constant */ - if( !activeconstantinf ) - { - assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar)); - - if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) ) - { - assert(scalar != 0.0); - if( scalar * multconstant > 0.0 ) - { - activeconstant = SCIPsetInfinity(set); - activeconstantinf = TRUE; - } - else - { - activeconstant = -SCIPsetInfinity(set); - activeconstantinf = TRUE; - } - } - else - activeconstant += scalar * multconstant; - } -#ifndef NDEBUG - else - { - assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 && - (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); - assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 && - (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); - } -#endif - - /* Note that the variable can have a nonzero constant but 0 scalar. */ - if( multscalar == 0.0 ) - continue; - - /* enter variable into list if not already present */ - assert(0 <= multvar->index && multvar->index < ntotalvars); - if( tmpscalars[multvar->index] == 0.0 ) - tmpvars[ntmpvars++] = multvar; - - /* transfer new scalar to dense array */ - tmpscalars[multvar->index] += scalar * multscalar; - assert(scalar * multscalar != 0.0); - } - - /* handle constant of multi-aggregation */ + /* handle constant */ if( !activeconstantinf ) { assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar)); - multconstant = SCIPvarGetMultaggrConstant(var); - if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) ) { assert(scalar != 0.0); @@ -4236,26 +4104,85 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( #ifndef NDEBUG else { - multconstant = SCIPvarGetMultaggrConstant(var); assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 && (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 && (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); } #endif - break; - case SCIP_VARSTATUS_FIXED: - case SCIP_VARSTATUS_ORIGINAL: - case SCIP_VARSTATUS_AGGREGATED: - case SCIP_VARSTATUS_NEGATED: - default: - /* case x = c, but actually we should not be here, since SCIPvarGetProbvarSum() returns a scalar of 0.0 for - * fixed variables and is handled already - */ - assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED); - assert(SCIPsetIsZero(set, var->glbdom.lb) && SCIPsetIsEQ(set, var->glbdom.lb, var->glbdom.ub)); + /* Note that the variable can have a nonzero constant but 0 scalar. */ + if( multscalar == 0.0 ) + continue; + + /* enter variable into list if not already present */ + assert(0 <= multvar->index && multvar->index < ntotalvars); + if( tmpscalars[multvar->index] == 0.0 ) + { + varstatus = SCIPvarGetStatus(multvar); + if( varstatus == SCIP_VARSTATUS_LOOSE || varstatus == SCIP_VARSTATUS_COLUMN ) + { + /* store active variables */ + if( nactivevars >= activevarssize ) + { + activevarssize *= 2; + SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) ); + assert(nactivevars <= activevarssize); + } + activevars[nactivevars++] = multvar; + } + else if( varstatus == SCIP_VARSTATUS_MULTAGGR ) + { + /* ensure storage */ + if( ntmpvars >= tmpvarssize ) + { + tmpvarssize *= 2; + SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) ); + assert(ntmpvars <= tmpvarssize); + } + tmpvars[ntmpvars++] = var; + } + } + + /* transfer new scalar to dense array in any case */ + tmpscalars[multvar->index] += scalar * multscalar; + assert(scalar * multscalar != 0.0); + } + + /* handle constant of multi-aggregation */ + if( !activeconstantinf ) + { + assert(!SCIPsetIsInfinity(set, scalar) && !SCIPsetIsInfinity(set, -scalar)); + + multconstant = SCIPvarGetMultaggrConstant(var); + + if( SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant) ) + { + assert(scalar != 0.0); + if( scalar * multconstant > 0.0 ) + { + activeconstant = SCIPsetInfinity(set); + activeconstantinf = TRUE; + } + else + { + activeconstant = -SCIPsetInfinity(set); + activeconstantinf = TRUE; + } + } + else + activeconstant += scalar * multconstant; + } +#ifndef NDEBUG + else + { + multconstant = SCIPvarGetMultaggrConstant(var); + assert(!SCIPsetIsInfinity(set, activeconstant) || !(scalar * multconstant < 0.0 && + (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); + assert(!SCIPsetIsInfinity(set, -activeconstant) || !(scalar * multconstant > 0.0 && + (SCIPsetIsInfinity(set, multconstant) || SCIPsetIsInfinity(set, -multconstant)))); } +#endif } /* return results */ @@ -4268,7 +4195,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) ) { - /* if the activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */ + /* if activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */ if( activeconstantinf ) *constant = activeconstant; else @@ -4293,6 +4220,8 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); assert(0 <= var->index && var->index < ntotalvars); + + /* due to cancelation, the scalar could become 0 */ if( tmpscalars[var->index] != 0.0 ) { vars[*nvars] = var; @@ -4319,8 +4248,8 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( assert(SCIPsetIsInfinity(set, *constant) == ((*constant) == SCIPsetInfinity(set))); /*lint !e777*/ assert(SCIPsetIsInfinity(set, -(*constant)) == ((*constant) == -SCIPsetInfinity(set))); /*lint !e777*/ - SCIPsetFreeBufferArray(set, &activevars); SCIPsetFreeCleanBufferArray(set, &tmpscalars); + SCIPsetFreeBufferArray(set, &activevars); SCIPsetFreeBufferArray(set, &tmpvars); return SCIP_OKAY; From b562e1c441ef15fcdd370b771a046ea9744bc717 Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Thu, 1 Aug 2024 17:56:17 +0200 Subject: [PATCH 05/14] fix bug with putting wrong variable on stack --- src/scip/var.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scip/var.c b/src/scip/var.c index 895bfe929b..407bca5d30 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -4140,7 +4140,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( SCIP_CALL( SCIPsetReallocBufferArray(set, &tmpvars, tmpvarssize) ); assert(ntmpvars <= tmpvarssize); } - tmpvars[ntmpvars++] = var; + tmpvars[ntmpvars++] = multvar; } } From c7fcccb71a539cc72b100abd4e018dd086205cab Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Fri, 16 Aug 2024 18:51:07 +0200 Subject: [PATCH 06/14] fix call/assert for SCIPgetProbvarLinearSum --- src/scip/cons_logicor.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/scip/cons_logicor.c b/src/scip/cons_logicor.c index 1b2b74669d..c3dac02a4c 100644 --- a/src/scip/cons_logicor.c +++ b/src/scip/cons_logicor.c @@ -995,6 +995,7 @@ SCIP_RETCODE applyFixings( SCIP_Bool easycase; int nconsvars; int requiredsize; + int size = 1; int v2; nconsvars = 1; @@ -1004,15 +1005,17 @@ SCIP_RETCODE applyFixings( consvals[0] = 1.0; /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); /* if space was not enough we need to resize the buffers */ - if( requiredsize > nconsvars ) + if( requiredsize > size ) { SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); + size = requiredsize; - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); - assert(requiredsize <= nconsvars); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); + assert(nconsvars <= size); + assert(requiredsize <= size); } easycase = FALSE; @@ -1057,7 +1060,6 @@ SCIP_RETCODE applyFixings( SCIP_CONS* newcons; SCIP_Real lhs; SCIP_Real rhs; - int size; int k; /* it might happen that there are more than one multi-aggregated variable, so we need to get the whole probvar sum over all variables */ @@ -1083,13 +1085,15 @@ SCIP_RETCODE applyFixings( SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); /* if space was not enough(we found another multi-aggregation), we need to resize the buffers */ - if( requiredsize > nconsvars ) + if( requiredsize > size ) { SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); + size = requiredsize; - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); - assert(requiredsize <= nconsvars); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); + assert(nconsvars <= size); + assert(requiredsize <= size); } lhs = 1.0 - constant; From cabf22ecf4ddfd3143e80613036d62fa88a6f07a Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Mon, 7 Oct 2024 11:52:06 +0200 Subject: [PATCH 07/14] fix assert --- src/scip/cons_setppc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/scip/cons_setppc.c b/src/scip/cons_setppc.c index 69ee2731c4..b9b908193d 100644 --- a/src/scip/cons_setppc.c +++ b/src/scip/cons_setppc.c @@ -1978,14 +1978,16 @@ SCIP_RETCODE applyFixings( SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); /* if space was not enough (we found another multi-aggregation), we need to resize the buffers */ - if( requiredsize > nconsvars ) + if( requiredsize > size ) { - SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); - SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); + size = requiredsize; + SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, size) ); + SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, size) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); - assert(requiredsize <= nconsvars); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) ); + assert(requiredsize == size); } + assert(nconsvars <= size); /* compute sides */ if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) From 159c23b21c07731d7a57482dacda05b1c538f239 Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Sat, 9 Nov 2024 16:07:47 +0100 Subject: [PATCH 08/14] fix arguments --- src/scip/cons_pseudoboolean.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scip/cons_pseudoboolean.c b/src/scip/cons_pseudoboolean.c index b8c9b3628e..7d33f8ba34 100644 --- a/src/scip/cons_pseudoboolean.c +++ b/src/scip/cons_pseudoboolean.c @@ -5103,7 +5103,7 @@ SCIP_RETCODE correctConshdlrdata( activeconstant = 0.0; nactivevars = 1; SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activescalars, &nactivevars, nvars, - &activeconstant, &requiredsize, TRUE) ); + &activeconstant, &requiredsize) ); assert(requiredsize <= nvars); for( i = 0; i < nactivevars && del; ++i ) From 2f13feec1dae5635a71b64cadbbf360a928facd0 Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Sun, 10 Nov 2024 12:09:29 +0100 Subject: [PATCH 09/14] remove superfluous command (*nvars is set below) --- src/scip/var.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scip/var.c b/src/scip/var.c index b0ca2108c7..33dc44baaa 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -4191,8 +4191,6 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( { assert(vars != NULL); - *nvars = *requiredsize; - if( !SCIPsetIsInfinity(set, *constant) && !SCIPsetIsInfinity(set, -(*constant)) ) { /* if activeconstant is infinite, the constant pointer gets the same value, otherwise add the value */ From b79a072f0450bce1e7d3ec24bc2f215580b1c7de Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Sun, 10 Nov 2024 12:09:52 +0100 Subject: [PATCH 10/14] make assert more precise --- src/scip/var.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scip/var.c b/src/scip/var.c index 33dc44baaa..b1a397639f 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -4127,7 +4127,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( { activevarssize *= 2; SCIP_CALL( SCIPsetReallocBufferArray(set, &activevars, activevarssize) ); - assert(nactivevars <= activevarssize); + assert(nactivevars < activevarssize); } activevars[nactivevars++] = multvar; } From edd2ab249240341461f3edee806296fc0c84f4b2 Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Sun, 10 Nov 2024 12:42:41 +0100 Subject: [PATCH 11/14] clarify that requiredsize is an upper bound --- src/scip/scip_var.c | 11 ++++++----- src/scip/scip_var.h | 11 ++++++----- src/scip/var.c | 16 ++++++++++------ src/scip/var.h | 13 +++++++------ 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/scip/scip_var.c b/src/scip/scip_var.c index c407d0c4ff..264a7408d7 100644 --- a/src/scip/scip_var.c +++ b/src/scip/scip_var.c @@ -1708,11 +1708,12 @@ SCIP_RETCODE SCIPflattenVarAggregationGraph( * active variables, that is b_1*y_1 + ... + b_m*y_m + d. * * If the number of needed active variables is greater than the available slots in the variable array, nothing happens - * except that the required size is stored in the corresponding variable (requiredsize). Otherwise, the active variable - * representation is stored in the variable array, scalar array and constant. + * except that an upper bound on the required size is stored in the variable requiredsize; otherwise, the active + * variable representation is stored in the arrays. * * The reason for this approach is that we cannot reallocate memory, since we do not know how the memory has been - * allocated (e.g., by a C++ 'new' or SCIP functions). + * allocated (e.g., by a C++ 'new' or SCIP functions). Note that requiredsize is an upper bound due to possible + * cancelations. * * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes. @@ -1751,8 +1752,8 @@ SCIP_RETCODE SCIPgetProbvarLinearSum( SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c which * will chnage to constant d in the linear sum b_1*y_1 + ... + b_m*y_m + * d w.r.t. the active variables */ - int* requiredsize /**< pointer to store the required array size for the linear sum w.r.t. the - * active variables */ + int* requiredsize /**< pointer to store an upper bound on the required size for the linear sum + * w.r.t. the active variables */ ) { assert( scip != NULL ); diff --git a/src/scip/scip_var.h b/src/scip/scip_var.h index 29a7ced816..ccf0d88ff8 100644 --- a/src/scip/scip_var.h +++ b/src/scip/scip_var.h @@ -769,11 +769,12 @@ SCIP_RETCODE SCIPflattenVarAggregationGraph( * active variables, that is b_1*y_1 + ... + b_m*y_m + d. * * If the number of needed active variables is greater than the available slots in the variable array, nothing happens - * except that the required size is stored in the corresponding variable (requiredsize). Otherwise, the active variable - * representation is stored in the variable array, scalar array and constant. + * except that an upper bound on the required size is stored in the variable requiredsize; otherwise, the active + * variable representation is stored in the arrays. * * The reason for this approach is that we cannot reallocate memory, since we do not know how the memory has been - * allocated (e.g., by a C++ 'new' or SCIP functions). + * allocated (e.g., by a C++ 'new' or SCIP functions). Note that requiredsize is an upper bound due to possible + * cancelations. * * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes. @@ -813,8 +814,8 @@ SCIP_RETCODE SCIPgetProbvarLinearSum( SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c which * will chnage to constant d in the linear sum b_1*y_1 + ... + b_m*y_m + * d w.r.t. the active variables */ - int* requiredsize /**< pointer to store the required array size for the linear sum w.r.t. the - * active variables */ + int* requiredsize /**< pointer to store an upper bound on the required size for the linear sum + * w.r.t. the active variables */ ); /** transforms given variable, scalar and constant to the corresponding active, fixed, or diff --git a/src/scip/var.c b/src/scip/var.c index b1a397639f..b576cf38ba 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -3928,12 +3928,13 @@ SCIP_RETCODE SCIPvarFix( /** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant * - * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except - * that the required size is stored in the variable requiredsize; hence, if afterwards the required size is greater than the - * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays. + * If the number of needed active variables is greater than the available slots in the variable array, nothing happens + * except that an upper bound on the required size is stored in the variable requiredsize; otherwise, the active + * variable representation is stored in the arrays. * - * The reason for this approach is that we cannot reallocate memory, since we do not know how the - * memory has been allocated (e.g., by a C++ 'new' or SCIP functions). + * The reason for this approach is that we cannot reallocate memory, since we do not know how the memory has been + * allocated (e.g., by a C++ 'new' or SCIP functions). Note that requiredsize is an upper bound due to possible + * cancelations. */ SCIP_RETCODE SCIPvarGetActiveRepresentatives( SCIP_SET* set, /**< global SCIP settings */ @@ -3942,7 +3943,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( int* nvars, /**< pointer to number of variables and values in vars and scalars array */ int varssize, /**< available slots in vars and scalars array */ SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ - int* requiredsize /**< pointer to store the required array size for the active variables */ + int* requiredsize /**< pointer to store an uppper bound on the required size for the active variables */ ) { SCIP_VAR** activevars; @@ -4185,6 +4186,9 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( #endif } + /* Here, nactivevars is an upper bound on the required size, because of possible cancellation. We could compute the + * actual size, but this would need another loop through the active variables. We therefore take the upper bound. */ + /* return results */ *requiredsize = nactivevars; if( varssize >= *requiredsize ) diff --git a/src/scip/var.h b/src/scip/var.h index cfaf78c99f..5d96790316 100644 --- a/src/scip/var.h +++ b/src/scip/var.h @@ -403,12 +403,13 @@ SCIP_RETCODE SCIPvarFix( /** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant * - * If the number of needed active variables is greater than the available slots in the variable array, nothing happens except - * that the required size is stored in the corresponding variable; hence, if afterwards the required size is greater than the - * available slots (varssize), nothing happens; otherwise, the active variable representation is stored in the arrays. + * If the number of needed active variables is greater than the available slots in the variable array, nothing happens + * except that an upper bound on the required size is stored in the variable requiredsize; otherwise, the active + * variable representation is stored in the arrays. * - * The reason for this approach is that we cannot reallocate memory, since we do not know how the - * memory has been allocated (e.g., by a C++ 'new' or SCIP functions). + * The reason for this approach is that we cannot reallocate memory, since we do not know how the memory has been + * allocated (e.g., by a C++ 'new' or SCIP functions). Note that requiredsize is an upper bound due to possible + * cancelations. */ SCIP_RETCODE SCIPvarGetActiveRepresentatives( SCIP_SET* set, /**< global SCIP settings */ @@ -417,7 +418,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( int* nvars, /**< pointer to number of variables and values in vars and vals array */ int varssize, /**< available slots in vars and scalars array */ SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ - int* requiredsize /**< pointer to store the required array size for the active variables */ + int* requiredsize /**< pointer to store an uppper bound on the required size for the active variables */ ); /** transforms given variable, scalar and constant to the corresponding active, fixed, or From ca90fa37a37424ffc2ceecff7b15feca21479d9b Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Sun, 10 Nov 2024 12:50:00 +0100 Subject: [PATCH 12/14] avoid small sizes for active variables array --- src/scip/var.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scip/var.c b/src/scip/var.c index b576cf38ba..04b39aefba 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -3997,7 +3997,7 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( SCIP_CALL( SCIPsetAllocBufferArray(set, &tmpvars, tmpvarssize) ); /* allocate memory for list of active variables */ - activevarssize = 2 * (*nvars); + activevarssize = MAX(10, 2 * (*nvars)); /* take the maximum to avoid small reallocations */ SCIP_CALL( SCIPsetAllocBufferArray(set, &activevars, activevarssize) ); /* allocate dense array for storing scalars (to avoid checking for duplicate variables) */ From 5fa4edb7b4615f03e349a62f76cc82326198af06 Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Sun, 10 Nov 2024 13:00:16 +0100 Subject: [PATCH 13/14] fix and improve usage of SCIPgetProbvarLinearSum --- src/scip/cons_setppc.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/scip/cons_setppc.c b/src/scip/cons_setppc.c index 9b112a7f8c..6b23ec1a67 100644 --- a/src/scip/cons_setppc.c +++ b/src/scip/cons_setppc.c @@ -1831,25 +1831,28 @@ SCIP_RETCODE applyFixings( SCIP_Bool easycase; int nconsvars; int requiredsize; + int consvarssize = 10; int v2; nconsvars = 1; - SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 1) ); - SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 1) ); + SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consvarssize) ); + SCIP_CALL( SCIPallocBufferArray(scip, &consvals, consvarssize) ); consvars[0] = repvar; consvals[0] = 1.0; /* get active variables for new constraint */ - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize) ); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, consvarssize, &constant, &requiredsize) ); /* if space was not enough we need to resize the buffers */ - if( requiredsize > nconsvars ) + if( requiredsize > consvarssize ) { - SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) ); - SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) ); + consvarssize = requiredsize; + SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, consvarssize) ); + SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, consvarssize) ); - SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize) ); - assert(requiredsize <= nconsvars); + SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, consvarssize, &constant, &requiredsize) ); + assert(requiredsize <= consvarssize); } + assert(nconsvars <= consvarssize); easycase = FALSE; From 01788438fe181f01d5da00655d12dcd800d4db50 Mon Sep 17 00:00:00 2001 From: Marc Pfetsch Date: Fri, 22 Nov 2024 16:22:40 +0100 Subject: [PATCH 14/14] do not need to sort --- src/scip/var.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/scip/var.c b/src/scip/var.c index 04b39aefba..23b9f3aa2f 100644 --- a/src/scip/var.c +++ b/src/scip/var.c @@ -4211,9 +4211,6 @@ SCIP_RETCODE SCIPvarGetActiveRepresentatives( } #endif - /* sort active variables for making the results consistent (todo: check whether this is necessary) */ - SCIPsortPtr((void**)activevars, SCIPvarComp, nactivevars); - /* copy active variable and scalar array to the given arrays */ *nvars = 0; for( v = 0; v < nactivevars; ++v )