add library parse function fpr jobshop1
- also extract common semantic analysis (Visitor) code
This commit is contained in:
parent
238cbe0e71
commit
8c1d6e12be
|
@ -1,4 +1,5 @@
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple, Sequence, Optional, Union
|
||||||
|
import arpeggio
|
||||||
|
|
||||||
grammar = """
|
grammar = """
|
||||||
# starting point for jobshop1 input file
|
# starting point for jobshop1 input file
|
||||||
|
@ -45,5 +46,44 @@ class JobShopProblem:
|
||||||
self.machines = machines
|
self.machines = machines
|
||||||
self.jobs = jobs
|
self.jobs = jobs
|
||||||
|
|
||||||
def __unicode__() -> str:
|
def __str__() -> str:
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
class JobShopVisitor(arpeggio.PTNodeVisitor):
|
||||||
|
"""contains visitor functions needed for both jobshop1 (list of instances)
|
||||||
|
and jobshop2 (single instance without name & description) input data"""
|
||||||
|
|
||||||
|
def visit_nonneg_num(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
|
if self.debug:
|
||||||
|
print("Converting non-negative integer", node.value)
|
||||||
|
return int(node.value)
|
||||||
|
|
||||||
|
def visit_machine(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
|
return int(node.value)
|
||||||
|
|
||||||
|
def visit_duration(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
|
return int(node.value)
|
||||||
|
|
||||||
|
def visit_num_machines(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
|
return int(node.value)
|
||||||
|
|
||||||
|
def visit_num_jobs(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
||||||
|
return int(node.value)
|
||||||
|
|
||||||
|
def visit_job_data(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]:
|
||||||
|
if self.debug:
|
||||||
|
print("Job data:\nnode:", type(node), "children:", children)
|
||||||
|
job_numbers = list(filter(lambda x: type(x) is int, children))
|
||||||
|
# job data needs to consist out of pairs of numbers
|
||||||
|
if len(job_numbers) % 2 ==1:
|
||||||
|
raise ParseError("Odd number of numbers in job data")
|
||||||
|
# returns list of (duration, machine) tuples
|
||||||
|
return list(zip(job_numbers[1::2], job_numbers[0::2]))
|
||||||
|
|
||||||
|
def visit_problem_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
||||||
|
if self.debug:
|
||||||
|
print("problem_data\nchildren:", children)
|
||||||
|
problem_data: List[List[Tuple(int, int)]] = [ children[i] for i in range(2, len(children))]
|
||||||
|
return JobShopProblem(children[0], children[1], problem_data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,12 @@
|
||||||
from arpeggio.cleanpeg import ParserPEG
|
from arpeggio.cleanpeg import ParserPEG
|
||||||
from typing import List, Tuple, Sequence, Optional
|
from typing import List, Tuple, Sequence, Optional, Union
|
||||||
import arpeggio
|
import arpeggio
|
||||||
|
|
||||||
from common import grammar, ParseError, JobShopProblem
|
from common import grammar, ParseError, JobShopProblem, JobShopVisitor
|
||||||
#from . import JobShopProblem
|
#from . import JobShopProblem
|
||||||
|
|
||||||
class JobShop1Visitor(arpeggio.PTNodeVisitor):
|
class JobShop1Visitor(JobShopVisitor):
|
||||||
|
"""instanciated for semantic analysis of parse_tree"""
|
||||||
def visit_nonneg_num(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
|
||||||
if self.debug:
|
|
||||||
print("Converting non-negative integer", node.value)
|
|
||||||
return int(node.value)
|
|
||||||
|
|
||||||
def visit_machine(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
|
||||||
return int(node.value)
|
|
||||||
|
|
||||||
def visit_duration(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
|
||||||
return int(node.value)
|
|
||||||
|
|
||||||
def visit_num_machines(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
|
||||||
return int(node.value)
|
|
||||||
|
|
||||||
def visit_num_jobs(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
|
|
||||||
return int(node.value)
|
|
||||||
|
|
||||||
def visit_job_data(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]:
|
|
||||||
if self.debug:
|
|
||||||
print("Job data:\nnode:", type(node), "children:", children)
|
|
||||||
job_numbers = list(filter(lambda x: type(x) is int, children))
|
|
||||||
# job data needs to consist out of pairs of numbers
|
|
||||||
if len(job_numbers) % 2 ==1:
|
|
||||||
raise ParseError("Odd number of numbers in job data")
|
|
||||||
# returns list of (duration, machine) tuples
|
|
||||||
return list(zip(job_numbers[1::2], job_numbers[0::2]))
|
|
||||||
|
|
||||||
def visit_problem_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
|
|
||||||
if self.debug:
|
|
||||||
print("problem_data\nchildren:", children)
|
|
||||||
problem_data: List[List[Tuple(int, int)]] = [ children[i] for i in range(2, len(children))]
|
|
||||||
return JobShopProblem(children[0], children[1], problem_data)
|
|
||||||
|
|
||||||
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:
|
||||||
|
@ -70,17 +38,20 @@ class JobShop1Visitor(arpeggio.PTNodeVisitor):
|
||||||
def visit_trim_ws(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> None:
|
def visit_trim_ws(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def parse_jobshop1_file(filename: Union[str, bytes]) -> List[JobShopProblem]:
|
||||||
|
"""Open file with jobshop1-formatted data (multiple problem instances),
|
||||||
|
parse it and return list of JobShopProblem s"""
|
||||||
|
|
||||||
#def visit_instance_list(self, node, children):
|
with open(filename) as datafile:
|
||||||
|
inputdata: str = datafile.read()
|
||||||
|
parse_tree = parser.parse(inputdata)
|
||||||
|
return arpeggio.visit_parse_tree(parse_tree, JobShop1Visitor())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = ParserPEG(grammar, "job_shop1", skipws=False)
|
print(parse_jobshop1_file("inputdata/jobshop1.txt"))
|
||||||
|
|
||||||
with open("./inputdata/jobshop1.txt") as datafile:
|
parser = ParserPEG(grammar, "job_shop1", skipws=False)
|
||||||
inputdata : str = datafile.read()
|
|
||||||
parse_tree = parser.parse(inputdata)
|
|
||||||
result = arpeggio.visit_parse_tree(parse_tree, JobShop1Visitor(debug=True))
|
|
||||||
print("\n\n\nResult:", result)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in a new issue