Given a local search (LS) algorithm for the optimisation version of the Golomb ruler problem. The algorithm is basically a hill-climbing algorithm that tries to minimise the constraint violations plus the length of the rulers. Try to run the algorithm on small as well as large problems such as those having ticks or more. The algorithm is the baseline algorithm, which you will compare the modified algorithms with. 1. Make 3 modifications to the given algorithm by copying the baseline algorithm into 3 separate cells. Select your modifications from the list below. The modifications should be clearly identifiable in each code block and please write your comments to explain the modifications. 2. Design an experiment to meaningfully compare the three algorithms with the baseline algorithm. Choose at least 3 criteria to use in your comparison and explain why you have chosen them Variable Selection: Inside its main while loop, the baseline algorithm selects a variable or tick randomly. You can try to find a strategy to select a variable. For example, select a variable leading to a difference that would appear the greatest number of times (of course more than one time) Value Selection: Inside its main while loop, the baseline algorithm randomly selects a value for a selected variable. You can try to find a strategy to select a value for the variable. For example, select a value leading to a difference that would appear the least number of times. Multiple Variable/Value Selection The baseline algorithm, inside its main while loop, selects only one variable and one value, and then use them to get a new solution. You could select one variable but multiple values or multiple variables and one value for each of them, and thus you could get a number of new solutions. Then, you could take the best one and then go for accept or reject. Tabu Strategy: if you uncomment the last line in the while loop and run the baseline algorithm, you will see the variables and values selected in the iterations. You will probably see that some variables and values are repeatedly selected within close proximity in the iterations. You can use the tabu strategy to avoid repetitions. The tabu strategy is as follows: Once a variable and/or value is selected, mark it with a future iteration number and then you will select that variable and/or value only from the iteration number. Configuration Checking: This is an altemative to the tabu strategy, but could be used for variables. Once a variable is selected, do not select the variable until one of its neighbouring variables (immediate previous and immediate next ones) has a new value. Improve Diversity: The baseline algorithm rejects all solutions worse than the current solution. You can use simulated annealing or another technique to accept some of those worse new solutions.
import time import numpy as np optimal ticks \#icks — give a value up to 12 maxlength ticks ticks +1 \# max length \# bigm will be used to different between constraint violation * and the object to minimise the length of the ruler bigm maxlength * maxlength * max number of iterations to run maxiter \# the limit on consecutive non-improving * iterations after which we assume search is stuck stuck * compute the fitness score of the solution * for each repetition of a difference, violation \# goes up by one. Total violation is muliplied \# by bigm to put more emphasis than the objective \# the last tick gives us the ruler length and \# that is actually the objective of the problem def evaluate(solution): violation * frequeny array is used to detect repetition freq for in range(maxlength) ] for i in range(ticks – 1): for in range , ticks : \# we assumed ticks are in ascending order \# so diff is always positive diff = solution – solution \# freg already non-zero means a violation if freq[diff] violation = violation +1 freq diff freq diff \# increase freq \# return weighted fitness score emphasising on violation return violation * bigm + solution [ticks – 1]
\# generate an initial solution \# randomly generate numbers up to maxlength \# sort the generated numbers. \# subtract first number from all to get a 0 starting \# for convenience, append maxlength def initialise(): solution np.random. choice(maxlength,ticks, replace=False) solution = sorted (solution) solution [ solution [i] – solution [0] for in range(ticks) solution. append (maxlength) return solution \# to measure the execution time start_time time.time () \# specify a seed for a reproducible run \# with no seed, a random seed is taken internally np.random.seed ) seed ) or any value \# get an initial solution and evaluate solution = initialise() score = evaluate(solution) \# best solution is initially empty with bigm score \# non-empty best solution is a feasible solution * With a score smaller than bigm bestsolution [] bestscore bigm \# if the initial solution is a feasible solution \# save it as the best solution, reduce maxlength * get another shorter initial solution until \# you get a solution that is not feasible. while (score < bestscore): print(“improve: “, solution, score) bestsolution [solution for in range(ticks)] bestscore score maxlength solution [ticks-1] solution = initialise() score = evaluate(solution) print(“init: “, solution, score, bestsolution, bestscore)
teration number of iterations lateau \# number of consecutive non-improving move run until maxiter and non-improving streak is not stuck hile iteration < maxiter and plateau < stuck: \# select a random variable i.e. tick, but not the first tick var = np.random.randint(1, ticks) \# if the selected var/tick has both side confied by neighbour ticks \# then there is no point in going with the variable, if (solution[var-1] solution[var] and solution[var+1] – 1 solution[var]): continue \# select a random variable i.e. tick, but not the first tick random.randint , ticks \# if the selected var/tick has both side confied by neighbour ticks * then there is no point in going with the variable, if (solution[var-1] solution[var] and solution [var+1] solution[var]): continue \# select a random value from the range between two neighbour variables newvalue np.random.randint (solution [var-1] +1 , solution[var +1 (solution [var] =: newvalue): continue \# once we know we have a variable and value to change the solution \# let us count it as an iteration of the search iteration iteration +1 \# keep a back up of the old solution and score oldvalue = solution var oldscore score * generate a new solution using the selected var and value and evaluate newsolution = [solution [i] for in range (len(solution))] \# just copy newsolution[var] = newvalue \# change the variable’s value newscore = evaluate (newsolution) \#feject or accept the new solution and update best solution (newscore > score): \# reject the solution plateau = plateau + 1 \# increase plateau length elif (newscore < score): \# we have an improvement score = newscore \# just copy the new score solution = newsolution \# copy the new solution plateau = 0 \# reset the plateau, since we have an improvement \#if we have a new best solution, update, and also improve as \#has been done with the initial solution while (score < bestscore): print(“improve: “, solution, score) bestsolution = [solution[i] for i in range(ticks)] * reject or accept the new solution and update best solution if (newscore > score): \# reject the solution plateau = plateau +1 \# increase plateau length elif (newscore < score): \# we have an improvement score = newscore \# just copy the new score solution = newsolution \# copy the new solution plateau \# reset the plateau, since we have an improvement \# if we have a new best solution, update, and also improve as * has been done with the initial solution while (score < bestscore): print(“improve: “, solution, score) bestsolution [solution for in range(ticks)]
bestscore score maxlength solution[ticks – 1] solution = initialise() score = evaluate(solution) \# uncomment the following line to see detailed information about each iteration print(var, oldvalue, newvalue, oldscore, newscore, solution, score, bestsolution, bestscore) end_time time time () ; if (bestscore bigm): print(“no solution found”) else: \# get the regular and the inverted solutions \# We made sure solutions start from 0 regardless of the solving method length = bestsolution[ticks – 1] regular [bestsolution [ ] for in range(ticks)] inverted [length – regular[ticks – 1 – i] for i in range(ticks)] \# print the solutions print(“ticks: “, ticks, “length: “, length, “optimal: “, optimal[ticks]) print(“regular: “, regular) print( “inverted: “, inverted) print(“cputime: “, end_time – start_time) improve: init: improve: improve: improve: improve: ticks: 6 length: 21 optimal: 17 regular: inverted: cputime: 0.37215614318847656
Read more here: Source link