#!/bin/bash
###############################################################################
# This hook is to tune the CPLEX software.
#
# PARAMETERS:
# $1 is the candidate configuration number
# $2 is the instance ID
# $3 is the seed
# $4 is the instance name
# The rest ($* after `shift 4') are parameters to the run of CPLEX
#
# RETURN VALUE:
# This hook should print a single numerical value (the value to be minimized)
# or a numerical value + the execution time when using maxBudgetTime
###############################################################################

EXE=/home/ibm/cplex-studio/12.10.0.0/CPLEX_Studio/cplex/bin/x86-64_linux/cplex

#check units for this
#MEMORY_LIMIT=$(( 3072 * 1024 * 1024 ))
#MEMORY_LIMIT=900


CANDIDATE=$1
INSTANCEID=$2
SEED=$3
INSTANCE=$4
shift 4 || exit 1
CAND_PARAMS=$*

RUNTIME_LIMIT=280
COST_LB=0  #Use for Maximization Case
#COST_LB=100000000  #Use for Minimization Case
PENALTY=$(( $RUNTIME_LIMIT ))

STDOUT="./Configurations/c${CANDIDATE}-${INSTANCEID}.stdout"
STDERR="./Configurations/c${CANDIDATE}-${INSTANCEID}.stderr"
STDPAR="./Configurations/c${CANDIDATE}-${INSTANCEID}.stdpar"

WORK_DIR="c${CANDIDATE}-${RANDOM}"

cat <<EOF > $STDPAR
set logfile *
read $INSTANCE
set workdir $WORK_DIR
set timelimit $RUNTIME_LIMIT
EOF

i=0
SIMPLEX_PER_S="no"
PERTURB_CONS="1e-6" #default value for option simple perturbation switch no

IFS=" "

for ELEMENT in $CAND_PARAMS; do
    mod=$(( $i % 2 ))

    if [ "$mod" -eq "0" ]; then
      PNAME=${ELEMENT//'_'/' '}

    elif [ "$PNAME" == "mip strategy bbinterval" ]; then
        if [ "$ELEMENT" -eq "0" ]; then
            ELEMENT=1000
        fi
    elif [ "$PNAME" == "simplex perturbation switch" ]; then
        SIMPLEX_PER_S=$ELEMENT
    elif [ "$PNAME" == "perturbation constant" ]; then
        PERTURB_CONS=$ELEMENT
    else
         echo "set $PNAME $ELEMENT" >> $STDPAR  
    fi

    i=$(( $i + 1))
done

cat <<EOF >> $STDPAR
display settings all
opt
quit
EOF

#echo "./target-runner ${INSTANCE} ${CANDIDATE} ${RUNTIME_LIMIT} ${CAND_PARAMS}" >> "check.txt"

#echo "$EXE < ${STDPAR} 1> ${STDOUT} 2> ${STDERR}" >> "check.txt"
$EXE < ${STDPAR} 1> ${STDOUT} 2> ${STDERR}

# In case of error, we print the current time:
error() {
    echo "`TZ=UTC date`: error: $@" >&2
    exit 1
}

# The output of the candidate $CANDIDATE should be written in the file 
if [ ! -s "${STDOUT}" ]; then
    # In this case, the file does not exist. Let's exit with a value 
    # different from 0. In this case irace will stop with an error.
    error "${STDOUT}: No such file or directory"
fi

SOLVED="CRASHED"

TMP=$(cat ${STDOUT} | grep "Error termination")
if [ "$TMP" != "" ]; then
    SOLVED="TIMEOUT"
fi

TMP=$(cat ${STDOUT} | grep "MIP - Time limit exceeded")
if [ "$TMP" != "" ]; then
    SOLVED="TIMEOUT"
fi

TMP=$(cat ${STDOUT} | grep "MIP - Aborted")
if [ "$TMP" != "" ]; then
    SOLVED="TIMEOUT"
fi

TMP=$(cat ${STDOUT} | grep "MIP - Memory limit exceeded")
if [ "$TMP" != "" ]; then
    SOLVED="TIMEOUT"
fi

TMP=$(cat ${STDOUT} | grep "runsolver_max_cpu_time_exceeded")
if [ "$TMP" != "" ] ; then
    SOLVED="TIMEOUT"
fi

TMP=$(cat ${STDOUT} | grep "runsolver_max_memory_limit_exceeded")
if [ "$TMP" != "" ] ; then
    SOLVED="TIMEOUT"
fi

TMP=$(cat ${STDOUT} | grep "MIP - Integer optimal")
if [ "$TMP" != "" ] ; then
    SOLVED="SOLVED"
fi

TMP=$(cat ${STDOUT} | grep "MIP - Optimal")
if [ "$TMP" != "" ] ; then
    SOLVED="SOLVED"
fi

if [ "$SOLVED" == "TIMEOUT" ]; then
    TIME=$RUNTIME_LIMIT
    
    calc(){ awk "BEGIN { print "$*" }"; }

    s=$(cat ${STDOUT} | grep "MIP - Time limit exceeded, integer feasible")

    if [ "$s" != "" ] ; then

      pat1='Objective =  ([0-9]+\.[0-9]*|\.?[0-9]+)([eE][+-][0-9]+)?' # To find Objective

      pat2='([0-9]+\.[0-9]*|\.?[0-9]+)([eE][+-][0-9]+)?' # To collect Objective Value

      [[ $s =~ $pat1 ]] # first regex application

      [[ ${BASH_REMATCH[0]} =~ $pat2 ]] # second regex application

      objective=${BASH_REMATCH[0]}
      
      #COST=$(calc $objective) #Use for Minimization
      COST=$(calc $objective*-1) #Use for Maximization
    
#      if ! [[ "$COST" =~ ^[-+0-9.e]+$ ]] ; then
#        error "${STDOUT}: Output is not a number"
#      fi 
    fi   
    
    if [ "$s" == "" ] ; then
      COST=$COST_LB
    fi
             
    
elif [ "$SOLVED" == "CRASHED" ]; then
    TIME=$PENALTY
    COST=$COST_LB
else
    # runtime objective
    TIME=$(cat ${STDOUT} | grep "Solution time" | gawk -F " " '{print $4}')
#    if ! [[ "$TIME" =~ ^[-+0-9.e]+$ ]] ; then
#        error "${STDOUT}: Output is not a number"
#    fi 
    
    calc1(){ awk "BEGIN { print "$*" }"; }

    s1=$(cat ${STDOUT} | grep "MIP - Integer optimal solution")
    
    if [ "$s1" != "" ] ; then
        pat3='Objective =  ([0-9]+\.[0-9]*|\.?[0-9]+)([eE][+-][0-9]+)?' 

        pat4='([0-9]+\.[0-9]*|\.?[0-9]+)([eE][+-][0-9]+)?' 

        [[ $s1 =~ $pat3 ]] 

        [[ ${BASH_REMATCH[0]} =~ $pat4 ]] 

        objective1=${BASH_REMATCH[0]}
        
        #COST=$(calc1 $objective1) # Use for Minimization        
        COST=$(calc1 $objective1*-1) # Use for Maximization
    
    fi     
    
    if [ "$s1" == "" ] ; then
        COST=$(cat ${STDOUT} | grep "Current MIP best bound" | gawk -F " " '{print $6}')
        COST=$(calc1 $COST*-1)
    fi   
    
#    if ! [[ "$COST" =~ ^[-+0-9.e]+$ ]] ; then
#        error "${STDOUT}: Output is not a number"
#    fi     
      
fi

echo "$COST $TIME" 

#echo "SCOST: $COST ECOST ./target-runner ${INSTANCE} ${CANDIDATE} ${CAND_PARAMS}" >> "check.txt"

# We are done with our duty. Clean files and exit with 0 (no error).
#rm -rf "$WORK_DIR" "${STDOUT}" "${STDERR}" "${STDPAR}"
rm -rf "$WORK_DIR" "${STDERR}"
exit 0