#ifndef _PAPILO_CORE_SAVED_ROW_HPP_
#define _PAPILO_CORE_SAVED_ROW_HPP_
#include "papilo/core/Solution.hpp"
#include "papilo/core/postsolve/BoundStorage.hpp"
#include "papilo/core/postsolve/ReductionType.hpp"
#include "papilo/misc/Num.hpp"
#include "papilo/misc/StableSum.hpp"
#include "papilo/misc/Vec.hpp"
namespace papilo
{
template <typename REAL>
class SavedRow
{
private:
Num<REAL> num;
int row;
Vec<int> col_coefficients;
Vec<REAL> row_values;
REAL slack;
bool is_lhs_inf;
REAL lhs;
bool is_rhs_inf;
REAL rhs;
int length;
public:
SavedRow( const Num<REAL>& n, int i, const Vec<ReductionType>& types,
const Vec<int>& start, const Vec<int>& indices,
const Vec<REAL>& values, const Vec<REAL>& primal_solution )
{
int next_type = i - 1;
int next_but_one_type = i - 2;
int saved_row = start[next_type];
if( types[next_type] == ReductionType::kSaveRow )
saved_row = start[next_type];
else if( types[next_but_one_type] == ReductionType::kSaveRow )
saved_row = start[next_but_one_type];
else
assert( false );
row = indices[saved_row];
length = (int)values[saved_row];
is_lhs_inf = indices[saved_row + 1] == 1;
lhs = values[saved_row + 1];
is_rhs_inf = indices[saved_row + 2] == 1;
rhs = values[saved_row + 2];
col_coefficients.resize( length );
row_values.resize( length );
StableSum<REAL> slack_of_row{};
for( int j = 0; j < length; ++j )
{
int col_index = indices[saved_row + 3 + j];
REAL val = values[saved_row + 3 + j];
col_coefficients[j] = col_index;
row_values[j] = val;
slack_of_row.add( val * primal_solution[col_index] );
}
slack = slack_of_row.get();
}
bool
is_on_lhs()
{
return !is_lhs_inf && num.isFeasEq( slack, lhs );
}
bool
is_on_rhs()
{
return !is_rhs_inf && num.isFeasEq( slack, rhs );
}
int
getRow()
{
return row;
}
int
getLength()
{
return length;
}
REAL
getCoeffOfCol( int col )
{
for( int j = 0; j < length; ++j )
{
if( col_coefficients[j] == col )
return row_values[j];
}
assert( false );
return 0;
}
int
getCoeff( int index )
{
return col_coefficients[index];
}
REAL
getValue( int index )
{
return row_values[index];
}
VarBasisStatus
getVBS()
{
if( is_on_lhs() && is_on_rhs() )
return VarBasisStatus::FIXED;
else if( is_on_rhs() )
return VarBasisStatus::ON_UPPER;
else if( is_on_lhs() )
return VarBasisStatus::ON_LOWER;
else if( is_lhs_inf && is_rhs_inf && num.isZero( slack ) )
return VarBasisStatus::ZERO;
return VarBasisStatus::BASIC;
}
bool
is_violated( const Vec<REAL>& primal,
const BoundStorage<REAL>& stored_bounds )
{
for( int i = 0; i < length; i++ )
{
int index = col_coefficients[i];
REAL sol = primal[index];
bool is_lb_violated = !stored_bounds.col_infinity_lower[index] &&
num.isLT( sol, stored_bounds.col_lower[index] );
bool is_ub_violated = !stored_bounds.col_infinity_upper[index] &&
num.isGT( sol, stored_bounds.col_upper[index] );
if(is_lb_violated || is_ub_violated)
return true;
}
bool rhs_violated = !is_rhs_inf && num.isFeasGT( slack, rhs );
bool lhs_violated = !is_lhs_inf && num.isFeasLT( slack, lhs );
return rhs_violated || lhs_violated;
}
};
}
#endif