Merge branch 'devel' into simanneal
This commit is contained in:
commit
3aed7f52f5
|
@ -1,42 +0,0 @@
|
||||||
import arpeggio
|
|
||||||
from arpeggio.cleanpeg import ParserPEG
|
|
||||||
from typing import List, Tuple, Sequence, Optional, Union
|
|
||||||
|
|
||||||
from . import grammar, JobShopVisitor, JobShopProblem
|
|
||||||
|
|
||||||
class JobShop2Visitor(JobShopVisitor):
|
|
||||||
|
|
||||||
def visit_job_shop2(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
|
||||||
if self.debug:
|
|
||||||
print("job_shop2:\nchildren:", children)
|
|
||||||
problem = children[0]
|
|
||||||
if self.debug:
|
|
||||||
print("returning a", type(problem))
|
|
||||||
return problem
|
|
||||||
|
|
||||||
def parse_jobshop2_string(inputdata: str) -> JobShopProblem:
|
|
||||||
"""parse string of jobshop2-formatted data (single problem instance, no name & description)
|
|
||||||
and return JobShopProblem
|
|
||||||
Raises a ParseError exception on errors"""
|
|
||||||
try:
|
|
||||||
parse_tree = parser.parse(inputdata)
|
|
||||||
except arpeggio.NoMatch as e:
|
|
||||||
raise ParseError("Error while parsing problem input data at line {}, col {}:\n Rules {} did not match.".format(e.line, e.col, e.rules))
|
|
||||||
return arpeggio.visit_parse_tree(parse_tree, JobShop2Visitor())
|
|
||||||
|
|
||||||
def parse_jobshop2_file(filename: Union[str, bytes]) -> JobShopProblem:
|
|
||||||
"""Open file with jobshop2-formatted data (single problem instance, no name & description),
|
|
||||||
parse it and return JobShopProblem
|
|
||||||
Raises a ParseError exception on errors"""
|
|
||||||
|
|
||||||
with open(filename) as datafile:
|
|
||||||
inputdata: str = datafile.read()
|
|
||||||
return parse_jobshop2_string(inputdata)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
print(type(parse_jobshop2_file('../inputdata/jobshop2/ta13')))
|
|
||||||
|
|
||||||
parser = ParserPEG(grammar, "job_shop2", skipws=False)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -1,13 +1,14 @@
|
||||||
from typing import List, Tuple, Sequence, Optional, Union
|
from typing import List, Tuple
|
||||||
import arpeggio
|
import arpeggio
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
__all__ = ["jobshop1_parser", "jobshop2_parser"]
|
__all__ = ["js1_style", "js2_style"]
|
||||||
|
|
||||||
grammar = """
|
grammar = """
|
||||||
# starting point for jobshop1 input file
|
# starting point for jobshop1 input file
|
||||||
job_shop1 = skip_preface
|
job_shop1 = skip_preface
|
||||||
# eat away lines of preface, until first problem_instance is encountered; then the list of instances start
|
# eat away lines of preface, until first problem_instance is
|
||||||
|
# encountered; then the list of instances start
|
||||||
skip_preface = (!problem_instance r"[^\n]+" skip_preface) / (eol skip_preface) / instance_list
|
skip_preface = (!problem_instance r"[^\n]+" skip_preface) / (eol skip_preface) / instance_list
|
||||||
instance_list = problem_instance (sep_line trim_ws eol problem_instance eol?)* eof_sep
|
instance_list = problem_instance (sep_line trim_ws eol problem_instance eol?)* eof_sep
|
||||||
problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data
|
problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data
|
||||||
|
@ -31,18 +32,23 @@ grammar = """
|
||||||
machine = nonneg_num
|
machine = nonneg_num
|
||||||
duration = nonneg_num
|
duration = nonneg_num
|
||||||
# task data for 1 job
|
# task data for 1 job
|
||||||
job_data = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol
|
job_data = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
"""To be thrown when parsing goes wrong"""
|
"""To be thrown when parsing goes wrong"""
|
||||||
|
|
||||||
def __init__(self, message: str) -> None:
|
def __init__(self, message: str) -> None:
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
class JobShopProblem:
|
|
||||||
|
|
||||||
def __init__(self, jobs: int, machines: int, problem_data: List[List[Tuple[int, int]]], name: str = 'unnamed', description: str = '') -> None:
|
class JobShopProblem(list):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, jobs: int, machines: int,
|
||||||
|
problem_data: List[List[Tuple[int, int]]],
|
||||||
|
name: str = 'unnamed', description: str = '') -> None:
|
||||||
# check plausibility of input
|
# check plausibility of input
|
||||||
if len(problem_data) != jobs:
|
if len(problem_data) != jobs:
|
||||||
raise ParseError("Given number of jobs for problem \"{}\" differs from actual job data.".format(name))
|
raise ParseError("Given number of jobs for problem \"{}\" differs from actual job data.".format(name))
|
||||||
|
@ -51,54 +57,59 @@ class JobShopProblem:
|
||||||
|
|
||||||
self.description = description
|
self.description = description
|
||||||
self.name = name
|
self.name = name
|
||||||
self.problem_data = problem_data
|
|
||||||
self.machines = machines
|
self.machines = machines
|
||||||
self.jobs = jobs
|
self.jobs = jobs
|
||||||
|
super().__init__(problem_data)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.name
|
return "JobShopProblem " + str(self.name)
|
||||||
|
|
||||||
|
|
||||||
class JobShopVisitor(arpeggio.PTNodeVisitor):
|
class JobShopVisitor(arpeggio.PTNodeVisitor):
|
||||||
"""contains visitor functions needed for both jobshop1 (list of instances)
|
"""contains visitor functions needed for both jobshop1 (list of instances)
|
||||||
and jobshop2 (single instance without name & description) input data"""
|
and jobshop2 (single instance without name & description) input data"""
|
||||||
|
|
||||||
def visit_nonneg_num(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
def visit_nonneg_num(
|
||||||
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> int:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("Converting non-negative integer", node.value)
|
print("Converting non-negative integer", node.value)
|
||||||
return int(node.value)
|
return int(node.value)
|
||||||
|
|
||||||
def visit_machine(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
def visit_machine(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
return int(node.value)
|
return int(node.value)
|
||||||
|
|
||||||
def visit_duration(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
def visit_duration(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
return int(node.value)
|
return int(node.value)
|
||||||
|
|
||||||
def visit_num_machines(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
def visit_num_machines(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
return int(node.value)
|
return int(node.value)
|
||||||
|
|
||||||
def visit_num_jobs(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
def visit_num_jobs(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
return int(node.value)
|
return int(node.value)
|
||||||
|
|
||||||
def visit_job_data(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]:
|
def visit_job_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("Job data:\nnode:", type(node), "children:", children)
|
print("Job data:\nnode:", type(node), "children:", children)
|
||||||
job_numbers = list(filter(lambda x: type(x) is int, children))
|
job_numbers = list(filter(lambda x: type(x) is int, children))
|
||||||
# job data needs to consist out of pairs of numbers
|
# job data needs to consist out of pairs of numbers
|
||||||
if len(job_numbers) % 2 ==1:
|
if len(job_numbers) % 2 == 1:
|
||||||
raise ParseError("Odd number of numbers in job data")
|
raise ParseError("Odd number of numbers in job data")
|
||||||
# returns list of (duration, machine) tuples
|
# returns list of (duration, machine) tuples
|
||||||
return list(zip(job_numbers[1::2], job_numbers[0::2])) # [::2] returns only every second element of the list
|
# [::2] returns only every second element of the list
|
||||||
|
return list(zip(job_numbers[1::2], job_numbers[0::2]))
|
||||||
|
|
||||||
def visit_problem_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
def visit_problem_data(
|
||||||
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("problem_data\nchildren:", children)
|
print("problem_data\nchildren:", children)
|
||||||
# filter out newlines or other strings
|
# filter out newlines or other strings
|
||||||
cleaned_data = list(filter(lambda x: type(x) is not str, children))
|
cleaned_data = list(filter(lambda x: type(x) is not str, children))
|
||||||
problem_data: List[List[Tuple(int, int)]] = [ cleaned_data[i] for i in range(2, len(cleaned_data))]
|
problem_data: List[List[Tuple[int, int]]] = [
|
||||||
|
cleaned_data[i] for i in range(2, len(cleaned_data))]
|
||||||
problem = JobShopProblem(children[0], children[1], problem_data)
|
problem = JobShopProblem(children[0], children[1], problem_data)
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("\nreturning a", type(problem), "\n")
|
print("\nreturning a", type(problem), "\n")
|
||||||
print("problem_data:", problem_data)
|
print("problem_data:", problem_data)
|
||||||
return problem
|
return problem
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
from arpeggio.cleanpeg import ParserPEG
|
from arpeggio.cleanpeg import ParserPEG
|
||||||
from typing import List, Tuple, Sequence, Optional, Union
|
from typing import List, Union
|
||||||
import arpeggio
|
import arpeggio
|
||||||
|
|
||||||
from . import grammar, ParseError, JobShopProblem, JobShopVisitor
|
from . import grammar, JobShopProblem, JobShopVisitor
|
||||||
|
|
||||||
|
|
||||||
class JobShop1Visitor(JobShopVisitor):
|
class JobShop1Visitor(JobShopVisitor):
|
||||||
"""instanciated for semantic analysis of parse_tree"""
|
"""instanciated for semantic analysis of parse_tree"""
|
||||||
|
|
||||||
def visit_problem_instance(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
def visit_problem_instance(
|
||||||
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("problem_instance\nchildren:", children)
|
print("problem_instance\nchildren:", children)
|
||||||
problem: JobShopProblem = children[3]
|
problem: JobShopProblem = children[3]
|
||||||
|
@ -15,41 +18,52 @@ class JobShop1Visitor(JobShopVisitor):
|
||||||
problem.description = children[2]
|
problem.description = children[2]
|
||||||
return problem
|
return problem
|
||||||
|
|
||||||
def visit_instance_list(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
|
def visit_instance_list(
|
||||||
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("instance_list\nchildren:", children)
|
print("instance_list\nchildren:", children)
|
||||||
return list(filter(lambda x: isinstance(x, JobShopProblem), children))
|
return list(filter(lambda x: isinstance(x, JobShopProblem), children))
|
||||||
|
|
||||||
def visit_skip_preface(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
|
def visit_skip_preface(
|
||||||
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("skip_preface\nchildren:", children)
|
print("skip_preface\nchildren:", children)
|
||||||
return list(filter(lambda x: type(x) is list, children))[0]
|
return list(filter(lambda x: type(x) is list, children))[0]
|
||||||
|
|
||||||
# ignore eol nodes
|
# ignore eol nodes
|
||||||
def visit_eol(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> None:
|
def visit_eol(
|
||||||
return None
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> None:
|
||||||
# ignore trim_ws nodes
|
|
||||||
def visit_trim_ws(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> None:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def parse_jobshop1_string(inputdata: str) -> JobShopProblem:
|
# ignore trim_ws nodes
|
||||||
|
def visit_trim_ws(
|
||||||
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_string(inputdata: str) -> JobShopProblem:
|
||||||
"""parse string with jobshop1-formatted data (multiple problem instances)
|
"""parse string with jobshop1-formatted data (multiple problem instances)
|
||||||
and return list of JobShopProblem s"""
|
and return list of JobShopProblem s"""
|
||||||
parse_tree = parser.parse(inputdata)
|
parse_tree = parser.parse(inputdata)
|
||||||
return arpeggio.visit_parse_tree(parse_tree, JobShop1Visitor())
|
return arpeggio.visit_parse_tree(parse_tree, JobShop1Visitor())
|
||||||
|
|
||||||
def parse_jobshop1_file(filename: Union[str, bytes]) -> List[JobShopProblem]:
|
|
||||||
|
def parse_file(filename: Union[str, bytes]) -> List[JobShopProblem]:
|
||||||
"""Open file with jobshop1-formatted data (multiple problem instances),
|
"""Open file with jobshop1-formatted data (multiple problem instances),
|
||||||
parse it and return list of JobShopProblem s"""
|
parse it and return list of JobShopProblem s"""
|
||||||
|
|
||||||
with open(filename) as datafile:
|
with open(filename) as datafile:
|
||||||
inputdata: str = datafile.read()
|
inputdata: str = datafile.read()
|
||||||
return parse_jobshop1_string(inputdata)
|
return parse_string(inputdata)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print(parse_jobshop1_file("../inputdata/jobshop1.txt"))
|
print(parse_file("../inputdata/jobshop1.txt"))
|
||||||
|
|
||||||
|
|
||||||
parser = ParserPEG(grammar, "job_shop1", skipws=False)
|
parser = ParserPEG(grammar, "job_shop1", skipws=False)
|
||||||
|
|
53
src/Parser/js2_style.py
Normal file
53
src/Parser/js2_style.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import arpeggio
|
||||||
|
from arpeggio.cleanpeg import ParserPEG
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from . import grammar, JobShopVisitor, JobShopProblem, ParseError
|
||||||
|
|
||||||
|
|
||||||
|
class JobShop2Visitor(JobShopVisitor):
|
||||||
|
|
||||||
|
def visit_job_shop2(
|
||||||
|
self, node: arpeggio.ParseTreeNode,
|
||||||
|
children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
||||||
|
if self.debug:
|
||||||
|
print("job_shop2:\nchildren:", children)
|
||||||
|
problem = children[0]
|
||||||
|
if self.debug:
|
||||||
|
print("returning a", type(problem))
|
||||||
|
return problem
|
||||||
|
|
||||||
|
|
||||||
|
def parse_string(inputdata: str) -> JobShopProblem:
|
||||||
|
"""parse string of jobshop2-formatted data
|
||||||
|
(single problem instance, no name & description)
|
||||||
|
and return JobShopProblem
|
||||||
|
Raises a ParseError exception on errors"""
|
||||||
|
try:
|
||||||
|
parse_tree = parser.parse(inputdata)
|
||||||
|
except arpeggio.NoMatch as e:
|
||||||
|
raise ParseError(
|
||||||
|
"Error while parsing problem input data at line {}, col {}:\n"
|
||||||
|
"Rules {} did not match.".format(e.line, e.col, e.rules))
|
||||||
|
return arpeggio.visit_parse_tree(parse_tree, JobShop2Visitor())
|
||||||
|
|
||||||
|
|
||||||
|
def parse_file(filename: Union[str, bytes]) -> JobShopProblem:
|
||||||
|
"""Open file with jobshop2-formatted data
|
||||||
|
(single problem instance, no name & description),
|
||||||
|
parse it and return JobShopProblem
|
||||||
|
Raises a ParseError exception on errors"""
|
||||||
|
|
||||||
|
with open(filename) as datafile:
|
||||||
|
inputdata: str = datafile.read()
|
||||||
|
return parse_string(inputdata)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(parse_file('../inputdata/jobshop2/ta13'))
|
||||||
|
|
||||||
|
|
||||||
|
parser = ParserPEG(grammar, "job_shop2", skipws=False)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in a new issue