module OptionsReader use BranchAndBound_Options implicit none integer, parameter, private :: MAX_NUMBER_OPTIONS = 20 ! Name of the options file. character(len=15), parameter, private :: OPTIONS_FILE_NAME = 'algencan-bb.opt' ! Characters used to comment lines in the options file. character(len=15), parameter, private :: COMMENT_CHARACTERS = '#*' ! Valid options. character(len=30), parameter, private :: & NODE_SELECTION_TOKEN = 'NODE_SELECTION', & BRANCHING_RULE_TOKEN = 'BRANCHING_RULE', & MULTI_START_TOKEN = 'MULTI_START', & NUM_ROOT_RESOLUTIONS_TOKEN = 'NUM_ROOT_RESOLUTIONS', & NUM_NODE_RESOLUTIONS_TOKEN = 'NUM_NODE_RESOLUTIONS', & IT_SWITCH_BEST_BOUND_TOKEN = 'IT_SWITCH_BEST_BOUND', & INCREASE_NODE_RESOLUTIONS_TOKEN = 'INCREASE_NODE_RESOLUTIONS', & UPDATES_BEFORE_TRUST_TOKEN = 'UPDATES_BEFORE_TRUST', & ! VAR_SELECTION_PARAMETERS_TOKEN = 'VAR_SELECTION_PARAMETERS', & CUTOFF_TOKEN = 'CUTOFF', & BOUND_TOLERANCE_TOKEN = 'BOUND_TOLERANCE', & BOX_CONSTRAINED_SOLVER_TOKEN = 'BOX_CONSTRAINED_SOLVER', & SOLVE_ROUNDED_SOLUTION_TOKEN = 'SOLVE_ROUNDED_SOLUTION' ! Possible values. ! NODE SELECTION character(len=15), parameter, private :: NODE_SELECTION_STRINGS(4) = & (/ 'BEST_BOUND_RULE','BREADTH_FIRST ','DEPTH_FIRST ',& 'SWITCH_DF_BBR ' /) integer, parameter, private :: NODE_SELECTION_VALUES(4) = & (/ BEST_BOUND_RULE,BREADTH_FIRST,DEPTH_FIRST,SWITCH_DF_BBR /) ! BRANCHING VARIABLE SELECTION character(len=18), parameter, private :: BRANCHING_RULE_STRINGS(5) = & (/ 'LOWEST_INDEX_FIRST','MOST_FRACTIONAL ','RANDOM_VARIABLE ', & 'PSEUDO_COSTS ','STRONG_BRANCHING ' /) integer, parameter, private :: BRANCHING_RULE_VALUES(4) = & (/ LOWEST_INDEX_FIRST,MOST_FRACTIONAL,RANDOM_VARIABLE,PSEUDO_COSTS /) ! MULTI-START STRATEGIES character(len=14), parameter, private :: MULTI_START_STRINGS(2) = & (/ 'BEST_FEASIBLE ','FIRST_FEASIBLE' /) integer, parameter, private :: MULTI_START_VALUES(2) = & (/ BEST_FEASIBLE,FIRST_FEASIBLE /) ! BOX-CONSTRAINED SOLVERS character(len=6), parameter, private :: BOX_CONSTRAINED_SOLVERS_STRINGS(2) =& (/ 'GENCAN','ASA ' /) contains ! ************************************************************************ ! ************************************************************************ subroutine readOptions(options) implicit none type(bb_options), intent(out) :: options character(len=80) :: line character(len=80), dimension(MAX_NUMBER_OPTIONS) :: option,value integer :: opRead opRead = 0 ! Initialize the options with default options. call initializeOptions(options) open(20,err=100,file=OPTIONS_FILE_NAME,status='OLD') do while(.true.) ! Read a line. read(20,fmt=1000,err=400,end=200) line !read(20,err=400,end=200) line ! Remove spaces. line = trim(adjustl(line)) if(.not. isComment(line(1:1))) then call parseLine(line,option(opRead + 1),value(opRead + 1)) if(applyOption(options,option(opRead + 1),value(opRead + 1))) then opRead = opRead + 1 else stop end if end if end do ! NO SPECIFICATION FILE 100 continue write(*, 9000) OPTIONS_FILE_NAME ! CLOSING SPECIFICATION FILE 200 continue close(20) go to 500 ! ERROR READING THE SPECIFICATION FILE 400 continue write(*, 9010) OPTIONS_FILE_NAME go to 500 500 continue ! call printOptions(option,value,opRead) 1000 format(A80) 9000 format(/,' The options file ', A15, ' was not found.',/,& ' The default options for the Branch-And-Bound algorithm',& ' will be used.') 9010 format(/,' Error reading specification file ', A15, '.') end subroutine readOptions ! ************************************************************************ ! ************************************************************************ subroutine printOptions(option,value,opRead) implicit none ! SCALAR ARGUMENTS integer :: opRead ! ARRAY ARGUMENTS character(len=*), dimension(MAX_NUMBER_OPTIONS) :: option,value ! LOCAL SCALARS integer :: i if(opRead .gt. 0) then write(*,100) do i = 1, opRead write(*,200) option(i),value(i) end do else write(*,300) OPTIONS_FILE_NAME end if write(*,*) 100 format(/, ' Branch-And-Bound Options:') 200 format(' ', A40, ' ', A40) 300 format(/, ' No option specified in the file ', A15, '.') end subroutine printOptions ! ************************************************************************ ! ************************************************************************ logical function applyOption(options,option,value) implicit none type(bb_options), intent(in out) :: options character(len=*), intent(in) :: option,value ! LOCAL SCALARS integer :: i,index,int_value real(kind=8) :: real_value applyOption = .true. select case(option) case(NODE_SELECTION_TOKEN) if(isNodeSelectionOptionValid(value,index)) then call setNodeSelectionStrategy(options,NODE_SELECTION_VALUES(index)) return else write(*,200) value,NODE_SELECTION_TOKEN do i = 1,size(NODE_SELECTION_STRINGS) write(*,300) trim(adjustl(NODE_SELECTION_STRINGS(i))) end do applyOption = .false. return end if case(BRANCHING_RULE_TOKEN) if(isBranchingRuleOptionValid(value,index)) then call setBranchingVariableStrategy(options,BRANCHING_RULE_VALUES(index)) return else write(*,200) value,BRANCHING_RULE_TOKEN do i = 1,size(BRANCHING_RULE_STRINGS) write(*,300) trim(adjustl(BRANCHING_RULE_STRINGS(i))) end do applyOption = .false. return end if case(MULTI_START_TOKEN) if(isMultiStartOptionValid(value,index)) then call setMultiStartStrategy(options,MULTI_START_VALUES(index)) return else write(*,200) value,MULTI_START_TOKEN do i = 1,size(MULTI_START_STRINGS) write(*,300) trim(adjustl(MULTI_START_STRINGS(i))) end do applyOption = .true. return end if case(NUM_ROOT_RESOLUTIONS_TOKEN) read(value,*) int_value call setNumRootResolutions(options,int_value) return case(NUM_NODE_RESOLUTIONS_TOKEN) read(value,*) int_value call setNumNodeResolutions(options,int_value) return case(INCREASE_NODE_RESOLUTIONS_TOKEN) read(value,*) int_value call setNumNodeResolutionsIncrease(options,int_value) return case(IT_SWITCH_BEST_BOUND_TOKEN) read(value,*) int_value call setNumIterationsForBestBoundRule(options,int_value) return case(UPDATES_BEFORE_TRUST_TOKEN) read(value,*) int_value call setNumberOfUpdatesBeforeTrust(options,int_value) return case(CUTOFF_TOKEN) read(value,*) real_value call setCutOff(options,real_value) return case(BOUND_TOLERANCE_TOKEN) read(value,*) real_value call setBoundTolerance(options,real_value) return case(SOLVE_ROUNDED_SOLUTION_TOKEN) call setSolveRoundedSolution(options,.true.) return case(BOX_CONSTRAINED_SOLVER_TOKEN) if(isBoxConstrainedSolverOptionValid(value,index)) then call setBoxConstrainedSolver(options,MULTI_START_VALUES(index)) return else write(*,200) value,BOX_CONSTRAINED_SOLVER_TOKEN do i = 1,size(BOX_CONSTRAINED_SOLVERS_STRINGS) write(*,300) trim(adjustl(BOX_CONSTRAINED_SOLVERS_STRINGS(i))) end do applyOption = .false. return end if case default write(*,100) option end select applyOption = .false. 100 format(' Invalid option: ', A40) 200 format(' Invalid value: ', A40, /, & ' Possible values for ',A40,' are:') 300 format(' ', A20) end function applyOption ! ************************************************************************ ! ************************************************************************ subroutine parseLine(line,firstWord,secondWord) implicit none ! SCALAR ARGUMENTS character(len=*), intent(in) :: line character(len=*), intent(out) :: firstWord,secondWord integer :: i do i = 1, len(firstWord) firstWord(i:i) = '' secondWord(i:i) = '' end do do i = 1, len(line) if(line(i:i) .eq. ' ') then exit end if firstWord(i:i) = line(i:i) end do secondWord(1:len(line) - i) = line(i+1:len(line)) end subroutine parseLine ! ************************************************************************ ! ************************************************************************ logical function isNodeSelectionOptionValid(value,index) implicit none ! SCALAR ARGUMENTS character(len=*), intent(in) :: value integer, intent(out) :: index ! LOCAL SCALARS integer :: i do i = 1, size(NODE_SELECTION_STRINGS) if(value .eq. trim(NODE_SELECTION_STRINGS(i))) then isNodeSelectionOptionValid = .true. index = i return end if end do index = -1 isNodeSelectionOptionValid = .false. end function isNodeSelectionOptionValid ! ************************************************************************ ! ************************************************************************ logical function isBranchingRuleOptionValid(value,index) implicit none ! SCALAR ARGUMENTS character(len=*), intent(in) :: value integer, intent(out) :: index ! LOCAL SCALARS integer :: i do i = 1, size(BRANCHING_RULE_STRINGS) if(value .eq. trim(BRANCHING_RULE_STRINGS(i))) then isBranchingRuleOptionValid = .true. index = i return end if end do index = -1 isBranchingRuleOptionValid = .false. end function isBranchingRuleOptionValid ! ************************************************************************ ! ************************************************************************ logical function isMultiStartOptionValid(value,index) implicit none ! SCALAR ARGUMENTS character(len=*), intent(in) :: value integer, intent(out) :: index ! LOCAL SCALARS integer :: i do i = 1, size(MULTI_START_STRINGS) if(value .eq. trim(MULTI_START_STRINGS(i))) then isMultiStartOptionValid = .true. index = i return end if end do index = -1 isMultiStartOptionValid = .false. end function isMultiStartOptionValid ! ************************************************************************ ! ************************************************************************ logical function isBoxConstrainedSolverOptionValid(value,index) implicit none ! SCALAR ARGUMENTS character(len=*), intent(in) :: value integer, intent(out) :: index ! LOCAL SCALARS integer :: i do i = 1, size(BOX_CONSTRAINED_SOLVERS_STRINGS) if(value .eq. trim(BOX_CONSTRAINED_SOLVERS_STRINGS(i))) then isBoxConstrainedSolverOptionValid = .true. index = i return end if end do index = -1 isBoxConstrainedSolverOptionValid = .false. end function isBoxConstrainedSolverOptionValid ! ************************************************************************ ! ************************************************************************ logical function isComment(c) implicit none character, intent(in) :: c if(index(COMMENT_CHARACTERS,c) .gt. 0) then isComment = .true. else isComment = .false. end if end function isComment ! ************************************************************************ ! ************************************************************************ end module OptionsReader