-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from jointpoints/python
Version 1.0.0
- Loading branch information
Showing
37 changed files
with
29,770 additions
and
5,195 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,3 +36,6 @@ | |
|
||
# Build folders | ||
/Facility Arrangement Solver (test build for Windows, v.0.1) | ||
|
||
# Python cache | ||
*.pyc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
''' | ||
Facility Arrangement Solver for Python | ||
Version: 1.0.0 | ||
Author : Andrew Eliseev (JointPoints) | ||
''' | ||
from sys import argv | ||
from os import system | ||
from time import time | ||
from math import ceil | ||
import random | ||
import networkx | ||
import json | ||
|
||
|
||
|
||
def generate_instance(idx): | ||
# Choose the number of subject groups | ||
subject_group_count = random.randint(2, 10) | ||
# Choose the number of subjects in each group | ||
subject_count = {i : random.randint(1, 5) for i in range(subject_group_count)} | ||
# Construct a random production pipeline | ||
pipeline = networkx.gn_graph(subject_group_count) | ||
total_flows = {i : {j : 0 for j in range(subject_group_count)} for i in range(subject_group_count)} | ||
group_queue = [i for i in range(subject_group_count) if pipeline.in_degree(i) == 0] | ||
total_input = {i : 100 if i in group_queue else 0 for i in range(subject_group_count)} | ||
while group_queue != []: | ||
i = group_queue[0] | ||
for edge in pipeline.edges(i): | ||
total_flows[i][edge[1]] = total_input[i] // pipeline.out_degree(i) | ||
total_input[edge[1]] += total_flows[i][edge[1]] | ||
group_queue.append(edge[1]) | ||
del group_queue[0] | ||
# Determine the capacities and areas of the subject groups | ||
capacities = {i : ceil(total_input[i] / subject_count[i]) for i in range(subject_group_count)} | ||
areas = {i : random.randint(1, 2) for i in range(subject_group_count)} | ||
# Save the instance | ||
meta = {'created_by' : 'FAS benchmark random instance generator', 'spec' : '1.0.0', 'type' : 'fasg'} | ||
stuff = {str(i) : {'area' : areas[i], 'input_capacity' : capacities[i], 'output_capacity' : capacities[i]} for i in range(subject_group_count)} | ||
with open(f'benchmark_random_{idx}.fasg', 'w') as f: | ||
json.dump({'stuff' : stuff, 'meta': meta}, f, indent='\t', sort_keys=True) | ||
meta['type'] = 'fast' | ||
stuff = {str(i) : {str(j) : total_flows[i][j] for j in range(subject_group_count)} for i in range(subject_group_count)} | ||
with open(f'benchmark_random_{idx}.fast', 'w') as f: | ||
json.dump({'stuff' : stuff, 'meta': meta}, f, indent='\t', sort_keys=True) | ||
return | ||
|
||
|
||
|
||
def main(): | ||
random.seed(218199) | ||
valid_instances_count = int(argv[1]) | ||
if len(argv) == 2: | ||
for valid_instance_i in range(valid_instances_count): | ||
generate_instance(valid_instance_i + 1) | ||
else: | ||
for valid_instance_i in range(valid_instances_count): | ||
generate_instance(0) | ||
for a in ('linear --forcevanilla', 'cpr_linear --forcevanilla', 'linear', 'cpr_linear', 'linear_gfred', 'cpr_linear_gfred'): | ||
for h in (5, 7, 9, 11, 13): | ||
start_time = time() | ||
system(f'{argv[2]} ../fas/fas.py -o arrangement.sol -f g{h}:1x{h}:1x2 -g benchmark_random_0.fasg -t benchmark_random_0.fast -d m1 -a {a}') | ||
runtime = time() - start_time | ||
with open(f'report_{valid_instance_i + 1}.txt', 'a') as f: | ||
f.write(f'{a} {h} {runtime}\n') | ||
if runtime >= 1200: | ||
break | ||
return | ||
|
||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
''' | ||
Facility Arrangement Solver for Python | ||
Version: 1.0.0 | ||
Author : Andrew Eliseev (JointPoints) | ||
''' | ||
from tools.arrangement import * | ||
from ui import fas_interactive | ||
from re import match | ||
from sys import argv | ||
|
||
|
||
|
||
def parse_args(args): | ||
answer = {} | ||
arg_translate = \ | ||
{ | ||
'-o' : 'output', | ||
'--output' : 'output', | ||
'-f' : 'facility', | ||
'--facility' : 'facility', | ||
'-g' : 'groups', | ||
'--groups' : 'groups', | ||
'-t' : 'total_flows', | ||
'--totalflows' : 'total_flows', | ||
'-a' : 'algo', | ||
'--algorithm' : 'algo', | ||
'-d' : 'dist', | ||
'--distance' : 'dist', | ||
'--forcevanilla' : 'force_vanilla', | ||
'-l' : 'log', | ||
'--log' : 'log', | ||
} | ||
arg_specification = \ | ||
{ | ||
'output' : {None}, | ||
'facility' : {None}, | ||
'groups' : {None}, | ||
'total_flows' : {None}, | ||
'algo' : {'linear', 'cpr_linear', 'linear_gfred', 'cpr_linear_gfred'}, | ||
'dist' : {f'm{N}' for N in range(1, 51)} | {'moo', None}, | ||
'force_vanilla' : {0}, | ||
'log' : {None}, | ||
} | ||
arg_expected = True | ||
curr_arg = None | ||
for arg in args: | ||
if arg_expected: | ||
if arg in arg_translate: | ||
curr_arg = arg_translate[arg] | ||
if 0 in arg_specification[curr_arg]: | ||
answer[curr_arg] = True | ||
else: | ||
print('ERROR: Unknown command line argument. To get help execute:') | ||
print('\tpython fas.py') | ||
print('\thelp') | ||
exit(1) | ||
else: | ||
if (arg in arg_specification[curr_arg]) or (None in arg_specification[curr_arg]): | ||
answer[curr_arg] = arg | ||
else: | ||
print('ERROR: Invalid value of an argument. To get help execute:') | ||
print('\tpython fas.py') | ||
print('\thelp') | ||
exit(1) | ||
arg_expected = (not arg_expected) or (0 in arg_specification[curr_arg]) | ||
if 'algo' not in answer: | ||
answer['algo'] = 'cpr_linear' | ||
if 'dist' not in answer: | ||
answer['dist'] = 'm2' | ||
if 'force_vanilla' not in answer: | ||
answer['force_vanilla'] = False | ||
if 'log' not in answer: | ||
answer['log'] = None | ||
if ('output' not in answer) or ('facility' not in answer) or ('groups' not in answer): | ||
print('ERROR: One or more required arguments are missing. To get help execute:') | ||
print('\tpython fas.py') | ||
print('\thelp') | ||
exit(1) | ||
return answer | ||
|
||
|
||
|
||
def run(**kwargs): | ||
algo = \ | ||
{ | ||
'linear' : arrange_linear, | ||
'cpr_linear' : arrange_cpr_linear, | ||
'linear_gfred' : arrange_linear_gfred, | ||
'cpr_linear_gfred' : arrange_cpr_linear_gfred, | ||
} | ||
# Try to load data | ||
try: | ||
if match('g[0-9]+:[.0-9]+x[0-9]+:[.0-9]+x[0-9]+', kwargs['facility']) != None: | ||
kwargs['facility'] = kwargs['facility'][1:] | ||
row_count = int(kwargs['facility'][:kwargs['facility'].index(':')]) | ||
kwargs['facility'] = kwargs['facility'][kwargs['facility'].index(':')+1:] | ||
row_step = float(kwargs['facility'][:kwargs['facility'].index('x')]) | ||
kwargs['facility'] = kwargs['facility'][kwargs['facility'].index('x')+1:] | ||
column_count = int(kwargs['facility'][:kwargs['facility'].index(':')]) | ||
kwargs['facility'] = kwargs['facility'][kwargs['facility'].index(':')+1:] | ||
column_step = float(kwargs['facility'][:kwargs['facility'].index('x')]) | ||
kwargs['facility'] = kwargs['facility'][kwargs['facility'].index('x')+1:] | ||
area = int(kwargs['facility']) | ||
if row_count * column_count * area == 0: | ||
raise ValueError() | ||
points = {f'({i},{j})' : Point(column_step * i, row_step * j, area) for i in range(column_count) for j in range(row_count)} | ||
grid_size = (column_count, row_count, 1) if not kwargs['force_vanilla'] else None | ||
else: | ||
points = fas_load(kwargs['facility'], 'fasf') | ||
grid_size = None | ||
groups = fas_load(kwargs['groups'], 'fasg') | ||
total_flows = fas_load(kwargs['total_flows'], 'fast') | ||
except RuntimeError as e: | ||
print(e) | ||
exit(1) | ||
except ValueError: | ||
print('ERROR: Grid parameters are invalid.') | ||
exit(1) | ||
# Compute the distance | ||
distance = {} | ||
if kwargs['dist'] in {f'm{_}' for _ in range(1, 51)}: | ||
order = int(kwargs['dist'][1:]) | ||
for point1_name in points: | ||
for point2_name in points: | ||
if order == 1: | ||
distance[(point1_name, point2_name)] = abs(points[point1_name].x - points[point2_name].x) + abs(points[point1_name].y - points[point2_name].y) | ||
else: | ||
distance[(point1_name, point2_name)] = (abs(points[point1_name].x - points[point2_name].x)**order + abs(points[point1_name].y - points[point2_name].y)**order)**(1/order) | ||
elif kwargs['dist'] == 'moo': | ||
for point1_name in points: | ||
for point2_name in points: | ||
distance[(point1_name, point2_name)] = max(abs(points[point1_name].x - points[point2_name].x), abs(points[point1_name].y - points[point2_name].y)) | ||
# Run an arrangement algorithm | ||
try: | ||
algo[kwargs['algo']](points, distance, groups, total_flows, kwargs['output'], kwargs['log'], grid_size) | ||
except RuntimeError as e: | ||
print(e) | ||
return | ||
|
||
|
||
|
||
def main(): | ||
args = argv[1:] | ||
# If there are no input arguments given, launch an interactive mode | ||
if len(args) == 0: | ||
fas_interactive.run() | ||
else: | ||
run(**parse_args(args)) | ||
return | ||
|
||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Oops, something went wrong.