https://github.com/legraina/DynamicNurseScheduler
Raw File
Tip revision: aef751362239e9ade6448f3731a625c29c9a9f0f authored by Antoine Legrain on 25 October 2023, 20:54:55 UTC
Only publish docker image on version tag. (#33)
Tip revision: aef7513
docker-entrypoint.sh
#!/bin/bash

valgrindOPT="--leak-check=full --show-leak-kinds=all --track-origins=yes"
dataDir="datasets/INRC2/"
instance_description="n005w4_0_1-2-3-3"
eval="1"
retries=0

function printBashUsage {
  echo "This script will run the simulator and then the validator."
  echo "Usage:"
  echo "-h  | --help: display this message"
  echo "-d  | --dynamic: Add this flag if you'd like to run the dynamic version."
  echo "-i  | --instance: instance to simulate (must follow the pattern (data_weeks_history)). Default: ${instance_description}"
  echo "-p  | --param: config file for the solver parameters. Default: none"
  echo "-sc | --solver-config: same than -p | --param"
  echo "-gc | --generation-config: config file for the generation parameters. Default: none"
  echo "-ec | --evaluation-config: config file for the evaluation parameters. Default: none"
  echo "-s  | --seeds: seeds to run the simulator for each stage (e.g., 22-36-96-5). Default: random."
  echo "-t  | --timeout: timeout for the solver or the stage. Default: based on the number of nurses and weeks in the instance."
  echo "-o  | --output | --sol: directory for the output. Default: outfiles/{instance}/{timestamp} or outfiles/{instance}/{seeds}_{timestamp} if dynamic"
  echo "-g  | --goal: goal to reach for the cost of the solution. Used for the unit tests. Default: none."
  echo "-v  | --valgrind: use valgrind to run the code. Default: false."
  echo "-vo | --valgrind-options: options for valgrind. Default: ${valgrindOPT}."
  echo "-e  | --evaluate: use the validator to evaluate thee solution. Default: ${eval}."
  echo "-r  | --root-dir-path: set the path where the script should be run. Default: do not move."
  echo "--retries: set the number of times to retry a failed run. Default: ${retries}."
  echo "--dir: set the dataset directory of the instance. Default: ${dataDir}."
}

# load config arguments in one line
ARGS=()
while [ ! -z "$1" ]; do
    for v in $1; do
        ARGS+=($v)
    done
    shift 1;
done
echo "${ARGS[@]}"
# parse arguments
dynamic_args=""
other_args=""
i=0
while [ ! -z ${ARGS[${i}]} ]; do
  case ${ARGS[${i}]} in
    -h|--help) printBashUsage
      exit 0;;
   -i | --instance) instance_description=${ARGS[((i+1))]}; ((i+=2));;
   -s | --seeds) seeds=${ARGS[((i+1))]}; dynamic_args="${dynamic_args} -s ${ARGS[((i+1))]}"; ((i+=2));;
   -t | --timeout) timeout=${ARGS[((i+1))]}; dynamic_args="${dynamic_args} -t ${ARGS[((i+1))]}"; ((i+=2));;
    # add config files
   -p | --param) param=${ARGS[((i+1))]}; ((i+=2));;
   -sc | --solver-config) param=${ARGS[((i+1))]}; ((i+=2));;
   -gc | --generation-config) genParam=${ARGS[((i+1))]}; ((i+=2));;
   -ec | --evaluation-config) evalParam=${ARGS[((i+1))]}; ((i+=2));;
   -g | --goal) goal=${ARGS[((i+1))]}; ((i+=2));;
   -d | --dynamic) dynamic="1"; ((i++));;
   -v | --valgrind) valgrind="1"; ((i++));;
   -vo | --valgrind-options) valgrindOPT=${ARGS[((i+1))]}; ((i+=2));;
   -e | --evaluate) eval=${ARGS[((i+1))]}; ((i+=2));;
   -r | --root-dir-path) rootDir=${ARGS[((i+1))]}; ((i+=2));;
   -o | --output | --sol) outputDir=${ARGS[((i+1))]}; ((i+=2));;
   --pricer) pricer="1"; ((i+=1));;
   --retries) retries=${ARGS[((i+1))]}; ((i+=2));;
   --dir) dataDir=${ARGS[((i+1))]}; ((i+=2));;
   -*|--*) echo "Option unknown: ${ARGS[${i}]}. It will be passed to the scheduler."
      other_args="${other_args} ${ARGS[${i}]} ${ARGS[((i+1))]}"; ((i+=2));;
   *) echo "Cannot parse this argument: ${ARGS[${i}]}. It will be passed to the scheduler."
      other_args="${other_args} ${ARGS[${i}]}"; ((i+=1));;
  esac
done
dynamic_args="${dynamic_args} -i ${instance_description}"

# move to root dir if defined
if [ ! -z ${rootDir} ]; then
    cd ${rootDir}
fi

function run {
  # test pricer if defined
  if [ ! -z ${pricer} ]; then
    pCMD="./bin/pricer ${instance_description} ${other_args}"
    echo "Run: ${pCMD}"
    ${pCMD}
    return ${PIPESTATUS[0]}
  fi

  if [ -z ${dynamic} ]; then
    # parse inputs
    # parse the input competition instance name
    echo "Instance: ${instance_description}"
    parse=(`echo ${instance_description} | tr '.' ' ' `)
    parse_inrc2=(`echo ${instance_description} | tr '_' ' ' `)
    i_args="--instance ${instance_description}"
    if [ "${#parse[@]}" -eq 2 ]; then
      instance_description=${parse[0]}
    elif [ "${#parse_inrc2[@]}" -eq 3 ]; then
      instance=${parse_inrc2[0]}
      hist=${parse_inrc2[1]}
      weeks=${parse_inrc2[2]}
      i_args="--instance ${instance} --weeks ${weeks} --his ${hist}"
    else
      echo "Format of instance not recognized: ${instance_description}"
      exit 1;
    fi

    # create the root of output directory if it does not exist
    if [ -z ${outputDir} ]; then
      currenttime=$( date +%s )
      outputDir="outfiles/${instance_description}/${currenttime}"
      echo "Create output directory: ${outputDir}"
      mkdir -p "${outputDir}"
    fi

    # base output
    sCMD="./bin/staticscheduler --dir ${dataDir} --sol ${outputDir} ${i_args}"

    # set default timeout
    if [ -z ${timeout} ]; then
      timeout=30
    fi
    sCMD="${sCMD} --timeout ${timeout}"

    # set param file
    if [ ! -z ${param} ]; then
      # param="paramfiles/default.txt"
      sCMD="${sCMD} --param paramfiles/${param}"
    fi

    # add others args
    sCMD="${sCMD} ${other_args}"

    if [ -z ${valgrind} ]; then
      # run the scheduler
      echo "Run: ${sCMD}"
      ${sCMD} | tee ${outputDir}/output.txt
      ret=${PIPESTATUS[0]}

      # run the validator
      echo "Exit code: ${ret}"
      if [ ${ret} -eq 0 -a ${eval} -eq 1 -a ! -z ${weeks} ]; then
          ./validator.sh ${instance} ${weeks} ${hist} ${outputDir} --verbose
      fi
    else
      # run the scheduler with valgrind
      valgrindCMD="valgrind ${valgrindOPT}"
      echo "Run: ${valgrindCMD} ${sCMD}"
      ${valgrindCMD} ${sCMD}

      return 0
    fi
  else
    # generate script
    source ./scripts/writeDynamicRun.sh ${dynamic_args} ${other_args}

    # copy config files
    if [ ! -z ${param} ]; then
      cp "${param}" "${outputDir}/solverOptions.txt"
    fi
    if [ ! -z ${genParam} ]; then
      cp "${genParam}" "${outputDir}/generationOptions.txt"
    fi
    if [ ! -z ${evalParam} ]; then
      cp "${evalParam}" "${outputDir}/evaluationOptions.txt"
    fi

    # run script
    echo "Run: ./${scriptfile}:"
    cat "${scriptfile}"
    chmod +x *.jar
    cp validator.jar ./bin
    ./${scriptfile}
    ret=${PIPESTATUS[0]}
      rm -f ${scriptfile}
  fi

  # display the solution
  if [ ${ret} -eq 0 -a ${eval} -eq 1 ]; then
      cat ${outputDir}/validator.txt
  fi

  # if a goal is defined, test the total cost
  if [ -z "$goal" ]; then
    return 0
  fi

  # fetch the total cost and check if is the right one (in the bounds)
  bounds=(`echo ${goal} | tr '-' ' ' `)
  lb=${bounds[0]}
  ub=${bounds[${#bounds[@]}-1]}
  echo "lb=$lb; ub=$ub"

  # check if should return an error (lb=-1)
  if [ ${lb} == "E" ]; then
      if [ ${ret} -eq 0 ]; then
          return 1
      fi
      return 0
  fi

  # check bounds
  if [ ${lb} -gt ${ub} ]; then
    echo "error: lb > ub"
    return 1
  fi

  if [ ${eval} -eq 1 ]; then
      result=$(cat ${outputDir}/validator.txt | grep "Total cost:")
  else
      result=$(cat ${outputDir}/output.txt | grep "Objective value")
  fi
  echo ${result}
  if [ -z "$result" ]
  then
    echo "error: total cost not found"
    return 1
  fi

  rcost=$(echo ${result} | tr -dc '0-9')
  if [ ${rcost} -lt ${lb} ] || [ ${rcost} -gt ${ub} ]
  then
    echo "error: bounds not respected"
    return 1
  fi

  return 0
}

ret=1
try=0
while [[ $try -le $retries && $ret -gt 0 ]]
do
  run
  ret=$?
  ((try++))
  echo "Try: $try and exit code: $ret"
done

exit $ret
back to top