From f52396427043b3aceb0ccce6e752fb116e495227 Mon Sep 17 00:00:00 2001 From: Emil Karlsson <emil.karlssson@liu.se> Date: Thu, 17 Feb 2022 21:13:23 +0100 Subject: [PATCH] Instance creation script corrected - Incorrect file for instance file generation was previously added --- README.md | 1 + instances.py | 158 +++++++++++++++++++++++------------------ segmented_instances.sh | 32 ++++----- 3 files changed, 106 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index a9043f7..29b51b0 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Instance set II is generated according to description in E. Coban and J. N. Hook The instance generator is available in [instances.py](instances.py) and we have used Python 3.8 to generate them. To generate all instances used in our article perform the following command. ```bash +>>> # source virtual environment with python3.8 >>> sh segmented_instances.sh ``` diff --git a/instances.py b/instances.py index 03d76dd..84ae98a 100644 --- a/instances.py +++ b/instances.py @@ -2,6 +2,43 @@ A script to generate instances for the simple job shop problem with fixed cost according to the method described in REFERENCE. + +alpha * R +gamma1 * alpha * R +gamma2 * alpha * R +beta (dj - rj) + +Tight + +alpha = 0.5 +gamma1 = 0.5 +gamma2 = 1.0 + +- 60: beta = 1 / 20 +- 80: beta = 1 / 20 +- 100: beta = 1 / 24 +- 120: beta = 1 / 28 +- 140: beta = 1 / 32 +- 160: beta = 1 / 32? +- 180: beta = 1 / 32? +- 200: beta = 1 / 32? + +Wide + +alpha = 0.5 +gamma1 = 0.25 +gamma2 = 1.0 +beta = 0.035 + +- 60 +- 80 +- 100 +- 120 +- 140 +- 160 +- 180 +- 200 + Usage example: python instances.py test_file.dat """ @@ -20,105 +57,88 @@ from collections import namedtuple @dataclass(frozen=True, order=True) class Job: ID: int - release_time: int - deadline: int - + release_time: float + deadline: float + processing_time: float -@dataclass(frozen=True) -class MachineJob: - duration: int - resource: int - cost: int - -@dataclass(frozen=True) -class Machine: +@dataclass(frozen=True, order=True) +class Segment: ID: int - resource_limit: int - + start: float + end: float def preparse_line(line): return "".join(i for i in line.replace("<", "").replace("\n", "").replace(">", "").replace("[", "").replace("]", "") if i.isdigit() or i == " ") -def generate_instance(no_jobs=None, no_machines=None, alpha=1/3, release_date_on=False): +def generate_instance(no_jobs, alpha, gamma1, gamma2, beta, segments_percentage, time_scale): + TIME_SCALE = time_scale + segments = list() + assert no_jobs % round(1/segments_percentage) == 0 + no_segments = round(segments_percentage * no_jobs) # Always ten percent of all jobs + R = no_segments + for segment_id in range(no_segments): + start = round(segment_id * TIME_SCALE) + end = round((segment_id + 1) * TIME_SCALE) + segment = Segment(segment_id, start, end) + segments.append(segment) + jobs = list() - machines = list() - machine_job_info = dict() - capacity_limit = 10 # For all instances - L = 5 * no_jobs * (no_machines + 1) / no_machines for job_id in range(no_jobs): - capacity_usage = random.randint(1, 10) # (0, 10) -> same for all machines - max_processing_time = 0 - for machine_id in range(no_machines): - i = machine_id + 1 - processing_time = random.randint(i, 10 * i) - max_processing_time = max(max_processing_time, processing_time) - cost = random.randint(2 * (no_machines - i + 1), 20 * (no_machines - i + 1)) - machine_job = MachineJob(processing_time, capacity_usage, cost) - machine_job_info[machine_id, job_id] = machine_job - if release_date_on: - release_date = random.randrange(0, max_processing_time) # Same for all jobs - deadline = release_date + max_processing_time + random.randrange(0, max_processing_time) # Same for all jobs - else: - release_date = 0 - deadline = alpha * L - job = Job(job_id, release_date, deadline) + release_time = random.uniform(0, alpha * R) + deadline = release_time + random.uniform(gamma1 * alpha * R, gamma2 * alpha * R) + processing_time = random.uniform(0, beta * (deadline - release_time)) + job = Job(job_id, round(TIME_SCALE * release_time), round(TIME_SCALE * deadline), round(TIME_SCALE * processing_time)) jobs.append(job) - for machine_id in range(no_machines): - machine = Machine(machine_id, capacity_limit) - machines.append(machine) - return jobs, machines, machine_job_info + return tuple(jobs), tuple(segments) -def instance_to_str(jobs, machines, machine_job_info): +def instance_to_str(jobs: Tuple[Job], segments: Tuple[Segment]): instance_str = "" instance_str += f"JobCount = {len(jobs)} ;\n" - instance_str += f"MachineCount = {len(machines)} ;\n" - instance_str += "machjob = [\n" + instance_str += f"SegmentCount = {len(segments)} ;\n" + instance_str += "Job = [\n" - for machine in machines: - machine_str = "[" - for job in jobs: - machine_job = machine_job_info[machine.ID, job.ID] - job_str = f"<{machine_job.duration} {machine_job.resource} {machine_job.cost}> " - machine_str += job_str - machine_str += "]\n" - instance_str += machine_str + machine_str = "[" + for job in jobs: + job_str = f"<{job.release_time} {job.deadline} {job.processing_time}> " + machine_str += job_str + machine_str += "]\n" + instance_str += machine_str instance_str += "];\n" - limit_str = "Limit = [" - for machine in machines: - limit_str += f"{machine.resource_limit} " - limit_str += "];\n" - instance_str += limit_str - - job_str = "Job = [" - for job in jobs: - job_str += f"<{job.release_time} {job.deadline}> " - job_str += "]\n" - instance_str += job_str + segment_str = "Segment = [" + for segment in segments: + segment_str += f"<{segment.start} {segment.end} > " + segment_str += "];\n" + instance_str += segment_str return instance_str +# A segment is between two consecutive integers? if __name__ == "__main__": # Argument parser - parser = argparse.ArgumentParser(description='Generate an simple job shop problem with fixed cost instance') - parser.add_argument('-r', '--release_time', action='store_true', help='Specifies if the tasks should have unique release times.') - parser.add_argument('-m', '--no_machines', type=int, help='The number of machines', default=3) + parser = argparse.ArgumentParser(description='Generate a segmented feasibility problem') + parser.add_argument('-a', '--alpha', type=float, help='?', default=0.5) + parser.add_argument('-g1', '--gamma1', type=float, help='Control the lower limit of time windows', default=0.5) + parser.add_argument('-g2', '--gamma2', help="Control the upper limit of time windows", default=1, type=float) parser.add_argument('-s', '--seed', help="The seed used for randomisation", default=0, type=int) - parser.add_argument('-j', '--no_jobs', help="The number of jobs on the instance", default=20, type=int) - parser.add_argument('-a', '--alpha', help="Selection of parameter alpha", type=float, default=0.3) + parser.add_argument('-j', '--no_jobs', help="The number of jobs on the instance", default=60, type=int) + parser.add_argument('-b', '--beta', help="Control processing time relative time windows width", type=float, default=0.035) + parser.add_argument('-t', '--time_scale', help="Control the time scale", type=float, default=100) + parser.add_argument('--segments', help="Specify the percentage of jobs that are segments", type=float, default=0.1) parser.add_argument('instance', help='Path to instance that is created', type=str) args = parser.parse_args() random.seed(args.seed) - jobs, machines, machine_job_info = generate_instance(args.no_jobs, args.no_machines, args.alpha, args.release_time) - instance_str = instance_to_str(jobs, machines, machine_job_info) + jobs, segments = generate_instance(args.no_jobs, args.alpha, args.gamma1, args.gamma2, args.beta, args.segments, args.time_scale) + instance_str = instance_to_str(jobs, segments) print(instance_str) - with open(args.instance, 'w') as instance_file: - instance_file.write(instance_str) + if args.instance != 'dry': + with open(args.instance, 'w') as instance_file: + instance_file.write(instance_str) diff --git a/segmented_instances.sh b/segmented_instances.sh index 2a2b587..bdb8871 100644 --- a/segmented_instances.sh +++ b/segmented_instances.sh @@ -2,25 +2,25 @@ echo "Tight windows" for SEED in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 do - python instances_segmented.py "sms_segmented_instances_new/tight60j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.5 --seed $SEED -j 60 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/tight80j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.45 --seed $SEED -j 80 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/tight100j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.4 --seed $SEED -j 100 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/tight120j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.35 --seed $SEED -j 120 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/tight140j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.3 --seed $SEED -j 140 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/tight160j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.25 --seed $SEED -j 160 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/tight180j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.2 --seed $SEED -j 180 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/tight200j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.15 --seed $SEED -j 200 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight60j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.5 --seed $SEED -j 60 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight80j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.45 --seed $SEED -j 80 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight100j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.4 --seed $SEED -j 100 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight120j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.35 --seed $SEED -j 120 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight140j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.3 --seed $SEED -j 140 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight160j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.25 --seed $SEED -j 160 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight180j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.2 --seed $SEED -j 180 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/tight200j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.2 --beta 0.15 --seed $SEED -j 200 -t 1000 --segments 0.10 done echo "Wide windows" for SEED in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 do - python instances_segmented.py "sms_segmented_instances_new/wide60j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.5 --seed $SEED -j 60 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/wide80j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.45 --seed $SEED -j 80 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/wide100j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.4 --seed $SEED -j 100 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/wide120j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.35 --seed $SEED -j 120 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/wide140j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.30 --seed $SEED -j 140 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/wide160j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.25 --seed $SEED -j 160 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/wide180j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.20 --seed $SEED -j 180 -t 1000 --segments 0.10 - python instances_segmented.py "sms_segmented_instances_new/wide200j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.15 --seed $SEED -j 200 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide60j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.5 --seed $SEED -j 60 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide80j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.45 --seed $SEED -j 80 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide100j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.4 --seed $SEED -j 100 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide120j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.35 --seed $SEED -j 120 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide140j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.30 --seed $SEED -j 140 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide160j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.25 --seed $SEED -j 160 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide180j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.20 --seed $SEED -j 180 -t 1000 --segments 0.10 + python3.8 instances.py "sms_sdspmtw__instance_set_ii/wide200j1000s$SEED.dat" --gamma1 0.0 --gamma2 0.5 --beta 0.15 --seed $SEED -j 200 -t 1000 --segments 0.10 done -- GitLab