@@ -449,35 +449,6 @@ HighsStatus Highs::addColsInterface(
449449 local_colLower, local_colUpper, options.infinite_bound ),
450450 return_status, " assessBounds" );
451451 if (return_status == HighsStatus::kError ) return return_status;
452- if (lp.user_bound_scale_ ) {
453- // Assess and apply any user bound scaling
454- if (!boundScaleOk (local_colLower, local_colUpper, lp.user_bound_scale_ ,
455- options.infinite_bound )) {
456- highsLogUser (options_.log_options , HighsLogType::kError ,
457- " User bound scaling yields infinite bound\n " );
458- return HighsStatus::kError ;
459- }
460- double bound_scale_value = std::pow (2 , lp.user_bound_scale_ );
461- for (HighsInt iCol = 0 ; iCol < ext_num_new_col; iCol++) {
462- local_colLower[iCol] *= bound_scale_value;
463- local_colUpper[iCol] *= bound_scale_value;
464- }
465- }
466- if (lp.user_cost_scale_ ) {
467- // Assess and apply any user cost scaling
468- if (!costScaleOk (local_colCost, lp.user_cost_scale_ ,
469- options.infinite_cost )) {
470- highsLogUser (options_.log_options , HighsLogType::kError ,
471- " User cost scaling yields infinite cost\n " );
472- return HighsStatus::kError ;
473- }
474- double cost_scale_value = std::pow (2 , lp.user_cost_scale_ );
475- for (HighsInt iCol = 0 ; iCol < ext_num_new_col; iCol++)
476- local_colCost[iCol] *= cost_scale_value;
477- }
478- // Append the columns to the LP vectors and matrix
479- appendColsToLpVectors (lp, ext_num_new_col, local_colCost, local_colLower,
480- local_colUpper);
481452 // Form a column-wise HighsSparseMatrix of the new matrix columns so
482453 // that is easy to handle and, if there are nonzeros, it can be
483454 // normalised
@@ -506,6 +477,20 @@ HighsStatus Highs::addColsInterface(
506477 // matrix columns
507478 local_a_matrix.start_ .assign (ext_num_new_col + 1 , 0 );
508479 }
480+ if (lp.user_cost_scale_ || lp.user_bound_scale_ ) {
481+ HighsUserScaleData user_scale_data;
482+ initialiseUserScaleData (lp, options_, user_scale_data);
483+ return_status = userScaleNewCols (local_colCost,
484+ local_colLower,
485+ local_colUpper,
486+ local_a_matrix,
487+ user_scale_data,
488+ options.log_options );
489+ if (return_status == HighsStatus::kError ) return HighsStatus::kError ;
490+ }
491+ // Append the columns to the LP vectors and matrix
492+ appendColsToLpVectors (lp, ext_num_new_col, local_colCost, local_colLower,
493+ local_colUpper);
509494 // Append the columns to LP matrix
510495 lp.a_matrix_ .addCols (local_a_matrix);
511496 if (lp_has_scaling) {
@@ -599,30 +584,11 @@ HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
599584 std::vector<double > local_rowUpper{ext_row_upper,
600585 ext_row_upper + ext_num_new_row};
601586
602- return_status = interpretCallStatus (
603- options_.log_options ,
587+ return_status = interpretCallStatus (options_.log_options ,
604588 assessBounds (options, " Row" , lp.num_row_ , index_collection,
605589 local_rowLower, local_rowUpper, options.infinite_bound ),
606590 return_status, " assessBounds" );
607591 if (return_status == HighsStatus::kError ) return return_status;
608- if (lp.user_bound_scale_ ) {
609- // Assess and apply any user bound scaling
610- if (!boundScaleOk (local_rowLower, local_rowUpper, lp.user_bound_scale_ ,
611- options_.infinite_bound )) {
612- highsLogUser (options_.log_options , HighsLogType::kError ,
613- " User bound scaling yields infinite bound\n " );
614- return HighsStatus::kError ;
615- }
616- double bound_scale_value = std::pow (2 , lp.user_bound_scale_ );
617- for (HighsInt iRow = 0 ; iRow < ext_num_new_row; iRow++) {
618- local_rowLower[iRow] *= bound_scale_value;
619- local_rowUpper[iRow] *= bound_scale_value;
620- }
621- }
622-
623- // Append the rows to the LP vectors
624- appendRowsToLpVectors (lp, ext_num_new_row, local_rowLower, local_rowUpper);
625-
626592 // Form a row-wise HighsSparseMatrix of the new matrix rows so that
627593 // is easy to handle and, if there are nonzeros, it can be
628594 // normalised
@@ -652,24 +618,25 @@ HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
652618 local_ar_matrix.start_ .assign (ext_num_new_row + 1 , 0 );
653619 }
654620 if (lp.user_bound_scale_ ) {
655- // Scale the columns corresponding to non-continuous variables,
656- // warning the user if small or large matrix entries are created
657- // as a result
658- HighsInt num_small_values;
659- HighsInt num_large_values;
660- if (!userScaleNonContinuousMatrix (lp.integrality_ ,
661- local_ar_matrix,
662- lp.user_bound_scale_ ,
663- options.small_matrix_value ,
664- options.large_matrix_value ,
665- num_small_values,
666- num_large_values)) {
667- return_status = HighsStatus::kWarning ;
668- highsLogUser (options_.log_options , HighsLogType::kWarning ,
669- " User bound scaling yields %d small matrix entries and %d small matrix entries\n " ,
670- int (num_small_values), int (num_large_values));
671- }
621+ HighsUserScaleData user_scale_data;
622+ initialiseUserScaleData (lp, options_, user_scale_data);
623+ const bool apply = false ;
624+ userScaleNewRows (lp.integrality_ ,
625+ local_rowLower,
626+ local_rowUpper,
627+ local_ar_matrix,
628+ user_scale_data,
629+ apply);
630+ return_status = userScaleStatus (options.log_options , user_scale_data);
631+ if (return_status == HighsStatus::kError ) return HighsStatus::kError ;
632+ userScaleNewRows (lp.integrality_ ,
633+ local_rowLower,
634+ local_rowUpper,
635+ local_ar_matrix,
636+ user_scale_data);
672637 }
638+ // Append the rows to the LP vectors
639+ appendRowsToLpVectors (lp, ext_num_new_row, local_rowLower, local_rowUpper);
673640 // Append the rows to LP matrix
674641 lp.a_matrix_ .addRows (local_ar_matrix);
675642 if (lp_has_scaling) {
@@ -981,19 +948,12 @@ HighsStatus Highs::changeCostsInterface(HighsIndexCollection& index_collection,
981948 if (return_status == HighsStatus::kError ) return return_status;
982949 HighsLp& lp = model_.lp_ ;
983950 if (lp.user_cost_scale_ ) {
984- // Assess and apply any user cost scaling
985- if (!costScaleOk (local_colCost, lp.user_cost_scale_ ,
986- options_.infinite_cost )) {
987- highsLogUser (options_.log_options , HighsLogType::kError ,
988- " User cost scaling yields infinite cost\n " );
989- return HighsStatus::kError ;
990- }
991- double cost_scale_value = std::pow (2 , lp.user_cost_scale_ );
992- for (HighsInt iCol = 0 ; iCol < num_cost; iCol++)
993- local_colCost[iCol] *= cost_scale_value;
951+ HighsUserScaleData user_scale_data;
952+ initialiseUserScaleData (lp, options_, user_scale_data);
953+ userScaleCosts (lp.integrality_ , local_colCost, user_scale_data, options_.log_options );
954+ if (return_status == HighsStatus::kError ) return HighsStatus::kError ;
994955 }
995956 changeLpCosts (lp, index_collection, local_colCost, options_.infinite_cost );
996-
997957 // Interpret possible introduction of infinite costs
998958 lp.has_infinite_cost_ = lp.has_infinite_cost_ || local_has_infinite_cost;
999959 assert (lp.has_infinite_cost_ == lp.hasInfiniteCost (options_.infinite_cost ));
@@ -1038,16 +998,11 @@ HighsStatus Highs::changeColBoundsInterface(
1038998 if (return_status == HighsStatus::kError ) return return_status;
1039999 HighsLp& lp = model_.lp_ ;
10401000 if (lp.user_bound_scale_ ) {
1041- // Assess and apply any user bound scaling
1042- if (!boundScaleOk (local_colLower, local_colUpper, lp.user_bound_scale_ ,
1043- options_.infinite_bound )) {
1044- highsLogUser (options_.log_options , HighsLogType::kError ,
1045- " User bound scaling yields infinite bound\n " );
1046- return HighsStatus::kError ;
1047- }
1048- userScaleContinuousColBounds (lp.integrality_ , local_colLower, local_colUpper, lp.user_bound_scale_ );
1001+ HighsUserScaleData user_scale_data;
1002+ initialiseUserScaleData (lp, options_, user_scale_data);
1003+ return_status = userScaleColBounds (lp.integrality_ , local_colLower, local_colUpper, user_scale_data, options_.log_options );
1004+ if (return_status == HighsStatus::kError ) return HighsStatus::kError ;
10491005 }
1050-
10511006 changeLpColBounds (lp, index_collection, local_colLower, local_colUpper);
10521007 // Update HiGHS basis status and (any) simplex move status of
10531008 // nonbasic variables whose bounds have changed
@@ -1092,20 +1047,11 @@ HighsStatus Highs::changeRowBoundsInterface(
10921047 if (return_status == HighsStatus::kError ) return return_status;
10931048 HighsLp& lp = model_.lp_ ;
10941049 if (lp.user_bound_scale_ ) {
1095- // Assess and apply any user bound scaling
1096- if (!boundScaleOk (local_rowLower, local_rowUpper, lp.user_bound_scale_ ,
1097- options_.infinite_bound )) {
1098- highsLogUser (options_.log_options , HighsLogType::kError ,
1099- " User bound scaling yields infinite bound\n " );
1100- return HighsStatus::kError ;
1101- }
1102- double bound_scale_value = std::pow (2 , lp.user_bound_scale_ );
1103- for (HighsInt iRow = 0 ; iRow < num_row_bounds; iRow++) {
1104- local_rowLower[iRow] *= bound_scale_value;
1105- local_rowUpper[iRow] *= bound_scale_value;
1106- }
1050+ HighsUserScaleData user_scale_data;
1051+ initialiseUserScaleData (lp, options_, user_scale_data);
1052+ return_status = userScaleRowBounds (local_rowLower, local_rowUpper, user_scale_data, options_.log_options );
1053+ if (return_status == HighsStatus::kError ) return HighsStatus::kError ;
11071054 }
1108-
11091055 changeLpRowBounds (lp, index_collection, local_rowLower, local_rowUpper);
11101056 // Update HiGHS basis status and (any) simplex move status of
11111057 // nonbasic variables whose bounds have changed
@@ -3090,88 +3036,35 @@ HighsStatus Highs::optionChangeAction() {
30903036 HighsLp& lp = model.lp_ ;
30913037 HighsInfo& info = this ->info_ ;
30923038 HighsOptions& options = this ->options_ ;
3093- const bool is_mip = lp.isMip ();
3094- HighsInt dl_user_bound_scale = 0 ;
30953039 HighsStatus return_status = HighsStatus::kOk ;
3096- const bool has_integrality = lp.integrality_ .size () > 0 ;
3097- // Ensure that user bound scaling does not yield infinite bounds or costs
3098- if (options.user_bound_scale != lp.user_bound_scale_ ) {
3099- if (!lp.userBoundScaleOk (options.user_bound_scale , options.infinite_bound )) {
3100- options.user_bound_scale = lp.user_bound_scale_ ;
3101- highsLogUser (options_.log_options , HighsLogType::kError ,
3102- " New user bound scaling yields infinite bound: reverting user "
3103- " bound scaling to %d\n " ,
3104- int (lp.user_bound_scale_ ));
3105- return_status = HighsStatus::kError ;
3106- } else {
3107- dl_user_bound_scale = options.user_bound_scale - lp.user_bound_scale_ ;
3108- }
3109- }
3110- if (dl_user_bound_scale) {
3111- double dl_user_bound_scale_value = std::pow (2 , dl_user_bound_scale);
3112- // Now update model status, data and solution with respect to
3113- // non-trivial user cost scaling
3114- this ->model_status_ = HighsModelStatus::kNotset ;
3115- if (has_integrality) {
3116- double objective_function_value = info.objective_function_value * dl_user_bound_scale_value;
3117- info.clear ();
3118- info.objective_function_value = objective_function_value;
3119- for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++) {
3120- if (lp.integrality_ [iCol] == HighsVarType::kContinuous ) {
3121- this ->solution_ .col_value [iCol] *= dl_user_bound_scale_value;
3122- } else {
3123- lp.col_cost_ [iCol] *= dl_user_bound_scale_value;
3124- }
3125- }
3126- } else {
3127- info.objective_function_value *= dl_user_bound_scale_value;
3128- info.num_primal_infeasibility = kHighsIllegalInfeasibilityCount ;
3129- info.max_primal_infeasibility *= dl_user_bound_scale_value;
3130- info.sum_primal_infeasibilities *= dl_user_bound_scale_value;
3131- for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
3132- this ->solution_ .col_value [iCol] *= dl_user_bound_scale_value;
3133- }
3134- for (HighsInt iRow = 0 ; iRow < lp.num_row_ ; iRow++)
3135- this ->solution_ .row_value [iRow] *= dl_user_bound_scale_value;
3136- info.primal_solution_status = kSolutionStatusNone ;
3137- // Update LP with respect to non-trivial user bound scaling
3138- lp.userBoundScale (options_.user_bound_scale );
3139- }
3140- // Now consider whether options.user_cost_scale has changed
3141- HighsInt dl_user_cost_scale = 0 ;
3142- if (options.user_cost_scale != lp.user_cost_scale_ ) {
3143- if (!model.userCostScaleOk (options.user_cost_scale , options.small_matrix_value ,
3144- options.large_matrix_value , options.infinite_cost )) {
3040+ HighsInt dl_user_cost_scale = options.user_cost_scale - lp.user_cost_scale_ ;
3041+ HighsInt dl_user_bound_scale = options.user_bound_scale - lp.user_bound_scale_ ;
3042+ if (dl_user_cost_scale || dl_user_bound_scale) {
3043+ HighsUserScaleData user_scale_data;
3044+ initialiseUserScaleData (lp, options_, user_scale_data);
3045+ user_scale_data.user_cost_scale = dl_user_cost_scale;
3046+ user_scale_data.user_bound_scale = dl_user_bound_scale;
3047+ return_status = userScaleLp (lp.integrality_ ,
3048+ lp.col_cost_ ,
3049+ lp.col_lower_ ,
3050+ lp.col_upper_ ,
3051+ lp.row_lower_ ,
3052+ lp.row_upper_ ,
3053+ lp.a_matrix_ ,
3054+ user_scale_data,
3055+ options.log_options );
3056+ if (return_status == HighsStatus::kError ) {
31453057 options.user_cost_scale = lp.user_cost_scale_ ;
3058+ options.user_bound_scale = lp.user_bound_scale_ ;
31463059 highsLogUser (options_.log_options , HighsLogType::kError ,
3147- " New user cost scaling yields excessive cost coefficient: "
3148- " reverting user cost scaling to %d\n " ,
3149- int (lp.user_cost_scale_ ));
3150- return_status = HighsStatus::kError ;
3151- } else {
3152- dl_user_cost_scale = options.user_cost_scale - lp.user_cost_scale_ ;
3060+ " New user cost/bound scaling yields excessive costs/bounds: "
3061+ " reverting user cost scaling to %d, and user bound scaling to %d\n " ,
3062+ int (lp.user_cost_scale_ ), int (lp.user_bound_scale_ ));
3063+ return HighsStatus::kError ;
31533064 }
3065+ this ->invalidateModelStatusSolutionAndInfo ();
3066+ this ->invalidateSolverData ();
31543067 }
3155- if (dl_user_cost_scale) {
3156- double dl_user_cost_scale_value = std::pow (2 , dl_user_cost_scale);
3157- // Now update model status, data and solution with respect to
3158- // non-trivial user cost scaling
3159- this ->model_status_ = HighsModelStatus::kNotset ;
3160- info.objective_function_value *= dl_user_cost_scale_value;
3161- info.num_dual_infeasibilities = kHighsIllegalInfeasibilityCount ;
3162- info.max_dual_infeasibility *= dl_user_cost_scale_value;
3163- info.sum_dual_infeasibilities *= dl_user_cost_scale_value;
3164- for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
3165- this ->solution_ .col_dual [iCol] *= dl_user_cost_scale_value;
3166- for (HighsInt iRow = 0 ; iRow < lp.num_row_ ; iRow++)
3167- this ->solution_ .row_dual [iRow] *= dl_user_cost_scale_value;
3168- info.dual_solution_status = kSolutionStatusNone ;
3169- // Update LP with respect to non-trivial user cost scaling
3170- model.userCostScale (options.user_cost_scale );
3171- }
3172- if (!user_bound_scale_ok || !user_cost_scale_ok) return HighsStatus::kError ;
3173- if (this ->iis_ .valid_ && options_.iis_strategy != this ->iis_ .strategy_ )
3174- this ->iis_ .invalidate ();
31753068 return HighsStatus::kOk ;
31763069}
31773070
@@ -4256,3 +4149,4 @@ void HighsLinearObjective::clear() {
42564149 this ->rel_tolerance = 0.0 ;
42574150 this ->priority = 0 ;
42584151}
4152+
0 commit comments