Merge remote-tracking branch 'origin/master'
# Conflicts: # scheduling.py
This commit is contained in:
commit
5950c1dab9
@ -84,8 +84,14 @@ def import_resource(res) -> Dict[str, model.Resource]:
|
|||||||
|
|
||||||
def import_resource_attributes(res, resources: Dict[str, model.Resource]):
|
def import_resource_attributes(res, resources: Dict[str, model.Resource]):
|
||||||
for record in res:
|
for record in res:
|
||||||
resources[record[0]].set_basic_attr(record[1])
|
resources[record[0]].set_basic_attr(record[2])
|
||||||
resources[record[0]].add_attr(record[2])
|
for attr in record[1].split(","):
|
||||||
|
resources[record[0]].add_attr(attr)
|
||||||
|
|
||||||
|
|
||||||
|
def import_process_resource(res, processes: Dict[str, model.Process]):
|
||||||
|
for record in res:
|
||||||
|
processes[record[0]].add_res_need(record[1], record[2])
|
||||||
|
|
||||||
|
|
||||||
def import_dataset():
|
def import_dataset():
|
||||||
@ -133,6 +139,11 @@ def import_dataset():
|
|||||||
|
|
||||||
import_resource_attributes(res, resources)
|
import_resource_attributes(res, resources)
|
||||||
|
|
||||||
|
cur.execute("SELECT * FROM aps_process_resource;")
|
||||||
|
res = cur.fetchall()
|
||||||
|
|
||||||
|
import_process_resource(res, processes)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return orders, products, processes, resources
|
return orders, products, processes, resources
|
||||||
|
4
model.py
4
model.py
@ -63,7 +63,7 @@ class Process:
|
|||||||
pcs_id: str,
|
pcs_id: str,
|
||||||
pcs_name: str,
|
pcs_name: str,
|
||||||
product: Product,
|
product: Product,
|
||||||
workspace: Workspace):
|
workspace: str):
|
||||||
|
|
||||||
self.pcs_id: str = pcs_id
|
self.pcs_id: str = pcs_id
|
||||||
self.pcs_name: str = pcs_name
|
self.pcs_name: str = pcs_name
|
||||||
@ -79,7 +79,7 @@ class Process:
|
|||||||
self.last_pcs: Optional[Process] = None
|
self.last_pcs: Optional[Process] = None
|
||||||
|
|
||||||
self.res_needs: List[Dict[str, any]] = []
|
self.res_needs: List[Dict[str, any]] = []
|
||||||
self.workspace: Workspace = workspace
|
self.workspace: str = workspace
|
||||||
|
|
||||||
def set_pre_last_pcs(self, prev_pcs: Optional[Process], last_pcs: Optional[Process]):
|
def set_pre_last_pcs(self, prev_pcs: Optional[Process], last_pcs: Optional[Process]):
|
||||||
self.prev_pcs: Process = prev_pcs
|
self.prev_pcs: Process = prev_pcs
|
||||||
|
145
runtime.py
145
runtime.py
@ -1,6 +1,8 @@
|
|||||||
|
from __future__ import annotations
|
||||||
import model
|
import model
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import List, Dict, Optional
|
from typing import List, Dict, Optional
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
class RuntimeProduct:
|
class RuntimeProduct:
|
||||||
@ -84,46 +86,53 @@ class RuntimeProcess:
|
|||||||
# 运行时资源需求
|
# 运行时资源需求
|
||||||
class RuntimeResourceNeed:
|
class RuntimeResourceNeed:
|
||||||
|
|
||||||
def __int__(self,
|
def __init__(self, runtime_process: RuntimeProcess, resource_attr: str, workspace: str,
|
||||||
process: model.Process,
|
|
||||||
resource_attr: str,
|
|
||||||
workspace: str,
|
|
||||||
start: datetime, end: datetime):
|
start: datetime, end: datetime):
|
||||||
if start < end:
|
if start > end:
|
||||||
raise RuntimeError("the start time must before the end time")
|
raise RuntimeError("the start time must before the end time")
|
||||||
|
|
||||||
self.process: model.Process = process
|
self.process: model.Process = runtime_process.process
|
||||||
self.resource_attr: str = resource_attr
|
self.resource_attr: str = resource_attr
|
||||||
self.workspace: str = workspace
|
self.workspace: str = workspace
|
||||||
self.start: datetime = start
|
self.start: datetime = start
|
||||||
self.end: datetime = end
|
self.end: datetime = end
|
||||||
|
self.plan_alloc_resources_id: List[str] = []
|
||||||
|
self.could_alloc = False
|
||||||
|
self.ddl = runtime_process.ddl
|
||||||
|
|
||||||
|
def add_plan_alloc_resource(self, runtime_resource_id: str):
|
||||||
|
self.plan_alloc_resources_id.append(runtime_resource_id)
|
||||||
|
|
||||||
|
|
||||||
# 运行时资源
|
# 运行时资源
|
||||||
class RuntimeResource:
|
class RuntimeResource:
|
||||||
|
|
||||||
def __init__(self, resource: model.Resource):
|
def __init__(self, resource: model.Resource, start_time: datetime):
|
||||||
self.resource: model.Resource = resource
|
self.resource: model.Resource = resource
|
||||||
self.workspace: str = self.resource.workspace
|
self.workspace: str = self.resource.workspace
|
||||||
self.basic_attr = self.resource.basic_attr
|
self.basic_attr = self.resource.basic_attr
|
||||||
self.resource_attrs = self.resource.attrs
|
self.resource_attrs = self.resource.attrs
|
||||||
self.schedules: List[RuntimeResourceNeed] = []
|
self.schedules: List[RuntimeResourceNeed] = []
|
||||||
|
self.start_time: datetime = start_time
|
||||||
|
|
||||||
def add_schedule(self, schedule: RuntimeResourceNeed) -> bool:
|
def add_schedule(self, schedule: RuntimeResourceNeed, do: bool) -> bool:
|
||||||
|
|
||||||
pre_need: Optional[RuntimeResourceNeed] = None
|
pre_need: Optional[RuntimeResourceNeed] = None
|
||||||
back_need: Optional[RuntimeResourceNeed] = None
|
back_need: Optional[RuntimeResourceNeed] = None
|
||||||
|
|
||||||
|
if schedule.ddl < self.start_time:
|
||||||
|
return False
|
||||||
|
|
||||||
for resource_need in self.schedules:
|
for resource_need in self.schedules:
|
||||||
if resource_need.end > schedule.start:
|
if resource_need.end > schedule.start > resource_need.start:
|
||||||
pre_need = resource_need
|
pre_need = resource_need
|
||||||
if back_need is not None \
|
if resource_need.start < schedule.end < resource_need.end:
|
||||||
and resource_need.start < resource_need.end:
|
|
||||||
back_need = resource_need
|
back_need = resource_need
|
||||||
|
|
||||||
if pre_need is not None or back_need is not None:
|
if pre_need is not None or back_need is not None:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
if do is True:
|
||||||
self.schedules.append(schedule)
|
self.schedules.append(schedule)
|
||||||
self.schedules = sorted(self.schedules, key=lambda need: need.start)
|
self.schedules = sorted(self.schedules, key=lambda need: need.start)
|
||||||
return True
|
return True
|
||||||
@ -131,14 +140,14 @@ class RuntimeResource:
|
|||||||
def get_earliest_available_free_times(self, duration: timedelta) -> datetime:
|
def get_earliest_available_free_times(self, duration: timedelta) -> datetime:
|
||||||
|
|
||||||
# 没有已分配任务
|
# 没有已分配任务
|
||||||
if self.schedules == 0:
|
if len(self.schedules) == 0:
|
||||||
return datetime.now()
|
return self.start_time
|
||||||
|
|
||||||
# 只有一个已分配任务
|
# 只有一个已分配任务
|
||||||
if self.schedules == 1:
|
if len(self.schedules) == 1:
|
||||||
target_schedule = self.schedules[0]
|
target_schedule = self.schedules[0]
|
||||||
if datetime.now() < target_schedule.start:
|
if self.start_time < target_schedule.start:
|
||||||
if target_schedule.start - datetime.now() > duration:
|
if target_schedule.start - self.start_time > duration:
|
||||||
return target_schedule.start - duration
|
return target_schedule.start - duration
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -148,8 +157,8 @@ class RuntimeResource:
|
|||||||
pre_schedule = self.schedules[i]
|
pre_schedule = self.schedules[i]
|
||||||
back_schedule = self.schedules[i + 1]
|
back_schedule = self.schedules[i + 1]
|
||||||
|
|
||||||
if datetime.now() < pre_schedule.start:
|
if self.start_time < pre_schedule.start and i == 0:
|
||||||
if pre_schedule.start - datetime.now() > duration:
|
if pre_schedule.start - self.start_time > duration:
|
||||||
return pre_schedule.start - duration
|
return pre_schedule.start - duration
|
||||||
|
|
||||||
elif back_schedule.start - pre_schedule.end > duration:
|
elif back_schedule.start - pre_schedule.end > duration:
|
||||||
@ -158,58 +167,120 @@ class RuntimeResource:
|
|||||||
return self.schedules[-1].end
|
return self.schedules[-1].end
|
||||||
|
|
||||||
|
|
||||||
# 资源池
|
|
||||||
class RuntimeResourcePool:
|
class RuntimeResourcePool:
|
||||||
|
|
||||||
def __init__(self, resources: List[model.Resource]):
|
def __init__(self, resources: List[model.Resource], start_time: datetime):
|
||||||
self.pool: List[RuntimeResource] = []
|
self.pool: Dict[str, RuntimeResource] = {}
|
||||||
|
self.start_time: datetime = start_time
|
||||||
|
|
||||||
for resource in resources:
|
for resource in resources:
|
||||||
runtime_resource = RuntimeResource(resource)
|
runtime_resource = RuntimeResource(resource, self.start_time)
|
||||||
self.pool.append(runtime_resource)
|
self.pool[runtime_resource.resource.rsc_id] = runtime_resource
|
||||||
|
|
||||||
|
# 资源分配操作
|
||||||
|
def alloc_resource(self, resource_needs: List[RuntimeResourceNeed]):
|
||||||
|
for resource_need in resource_needs:
|
||||||
|
if resource_need.could_alloc is False:
|
||||||
|
continue
|
||||||
|
for plan_alloc_resource_id in resource_need.plan_alloc_resources_id:
|
||||||
|
self.pool[plan_alloc_resource_id].add_schedule(resource_need, True)
|
||||||
|
|
||||||
|
def try_alloc_resource(self, resource_needs: List[RuntimeResourceNeed]) -> bool:
|
||||||
|
|
||||||
|
temp_pool = deepcopy(list(self.pool.values()))
|
||||||
|
|
||||||
|
# 已经满足的需求
|
||||||
|
fulfilled_needs = []
|
||||||
|
|
||||||
|
if_all_alloc = True
|
||||||
|
|
||||||
|
for resource_need in resource_needs:
|
||||||
|
|
||||||
|
if resource_need.could_alloc is True:
|
||||||
|
continue
|
||||||
|
|
||||||
def alloc_resource(self, resource_need: RuntimeResourceNeed) -> bool:
|
|
||||||
# 精确搜索
|
# 精确搜索
|
||||||
for runtime_resource in self.pool:
|
for runtime_resource in temp_pool:
|
||||||
# 排除不同车间
|
# 排除不同车间
|
||||||
if runtime_resource.workspace != resource_need.workspace:
|
if runtime_resource.workspace != resource_need.workspace:
|
||||||
continue
|
continue
|
||||||
if runtime_resource.basic_attr == resource_need.resource_attr:
|
if runtime_resource.basic_attr == resource_need.resource_attr:
|
||||||
if runtime_resource.add_schedule(resource_need) is True:
|
if runtime_resource.add_schedule(resource_need, False) is True:
|
||||||
return True
|
resource_need.add_plan_alloc_resource(runtime_resource.resource.rsc_id)
|
||||||
|
fulfilled_needs.append(resource_need)
|
||||||
|
runtime_resource.add_schedule(resource_need, True)
|
||||||
|
resource_need.could_alloc = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# 是否已经分配完成
|
||||||
|
if resource_need.could_alloc is False:
|
||||||
# 放宽条件搜索
|
# 放宽条件搜索
|
||||||
for runtime_resource in self.pool:
|
for runtime_resource in temp_pool:
|
||||||
# 排除不同车间
|
# 排除不同车间
|
||||||
if runtime_resource.workspace != resource_need.workspace:
|
if runtime_resource.workspace != resource_need.workspace:
|
||||||
continue
|
continue
|
||||||
if resource_need.resource_attr in runtime_resource.resource_attrs:
|
if resource_need.resource_attr in runtime_resource.resource_attrs:
|
||||||
if runtime_resource.add_schedule(resource_need) is True:
|
if runtime_resource.add_schedule(resource_need, False) is True:
|
||||||
return True
|
resource_need.add_plan_alloc_resource(runtime_resource.resource.rsc_id)
|
||||||
|
fulfilled_needs.append(resource_need)
|
||||||
|
runtime_resource.add_schedule(resource_need, True)
|
||||||
|
resource_need.could_alloc = True
|
||||||
|
break
|
||||||
|
|
||||||
return False
|
if resource_need not in fulfilled_needs:
|
||||||
|
if_all_alloc = False
|
||||||
|
|
||||||
def get_earliest_free_time(self, resource_need: RuntimeResourceNeed) -> datetime:
|
return if_all_alloc
|
||||||
|
|
||||||
|
def reset_earliest_free_start_time(self, resource_needs: List[RuntimeResourceNeed]) -> bool:
|
||||||
|
|
||||||
|
if_found = False
|
||||||
|
|
||||||
|
for resource_need in resource_needs:
|
||||||
|
|
||||||
|
if resource_need.could_alloc is True:
|
||||||
|
continue
|
||||||
|
|
||||||
earliest_time: Optional[datetime] = None
|
earliest_time: Optional[datetime] = None
|
||||||
|
|
||||||
duration = resource_need.end - resource_need.start
|
duration = resource_need.end - resource_need.start
|
||||||
|
|
||||||
# 精确搜索
|
# 精确搜索
|
||||||
for runtime_resource in self.pool:
|
for runtime_resource in self.pool.values():
|
||||||
|
# 排除不同车间
|
||||||
|
if runtime_resource.workspace != resource_need.workspace:
|
||||||
|
continue
|
||||||
if runtime_resource.basic_attr == resource_need.resource_attr:
|
if runtime_resource.basic_attr == resource_need.resource_attr:
|
||||||
temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration)
|
temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration)
|
||||||
|
# 时间不能超过DDL
|
||||||
|
if temp_earliest_time > resource_need.ddl - duration:
|
||||||
|
continue
|
||||||
if earliest_time is None or earliest_time > temp_earliest_time:
|
if earliest_time is None or earliest_time > temp_earliest_time:
|
||||||
earliest_time = temp_earliest_time
|
earliest_time = temp_earliest_time
|
||||||
|
|
||||||
# 优先利用对口资源
|
# 优先利用对口资源
|
||||||
if earliest_time is not None:
|
if earliest_time is not None:
|
||||||
return earliest_time
|
resource_need.start = earliest_time
|
||||||
|
|
||||||
# 放宽条件搜索
|
# 放宽条件搜索
|
||||||
for runtime_resource in self.pool:
|
else:
|
||||||
|
for runtime_resource in self.pool.values():
|
||||||
|
# 排除不同车间
|
||||||
|
if runtime_resource.workspace != resource_need.workspace:
|
||||||
|
continue
|
||||||
if resource_need.resource_attr in runtime_resource.resource_attrs:
|
if resource_need.resource_attr in runtime_resource.resource_attrs:
|
||||||
temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration)
|
temp_earliest_time = runtime_resource.get_earliest_available_free_times(duration)
|
||||||
|
# 时间不能超过DDL
|
||||||
|
if temp_earliest_time > resource_need.ddl - duration:
|
||||||
|
continue
|
||||||
if earliest_time is None or earliest_time > temp_earliest_time:
|
if earliest_time is None or earliest_time > temp_earliest_time:
|
||||||
earliest_time = temp_earliest_time
|
earliest_time = temp_earliest_time
|
||||||
|
|
||||||
return earliest_time
|
if earliest_time is None:
|
||||||
|
if_found = False
|
||||||
|
else:
|
||||||
|
resource_need.start = earliest_time
|
||||||
|
resource_need.end = earliest_time + duration
|
||||||
|
if_found = True
|
||||||
|
|
||||||
|
return if_found
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import runtime
|
|||||||
import model
|
import model
|
||||||
import csv
|
import csv
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta, date
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
import dataset_importer
|
import dataset_importer
|
||||||
@ -81,25 +81,53 @@ def products_processor(runtime_products: List[runtime.RuntimeProduct]):
|
|||||||
for item in runtime_products_processes_list:
|
for item in runtime_products_processes_list:
|
||||||
for runtime_process in item["runtimeProcess"]:
|
for runtime_process in item["runtimeProcess"]:
|
||||||
runtime_product: runtime.RuntimeProduct = item["runtimeProduct"]
|
runtime_product: runtime.RuntimeProduct = item["runtimeProduct"]
|
||||||
print(runtime_product.product.product_id, runtime_product.delay, runtime_process.process.pcs_id)
|
# print(runtime_product.product.product_id, runtime_product.delay, runtime_process.process.pcs_id)
|
||||||
|
|
||||||
return runtime_products_processes_list
|
return runtime_products_processes_list
|
||||||
|
|
||||||
|
|
||||||
# def resource_processor(resources: List[model.Resource], runtime_products_processes_list: List[Dict[str, any]]):
|
def resource_processor(runtime_products_processes_list: List[Dict[str, any]],
|
||||||
# resource_pool = runtime.RuntimeResourcePool(resources)
|
resource_pool: runtime.RuntimeResourcePool,
|
||||||
#
|
start_time: datetime):
|
||||||
# for item in runtime_products_processes_list:
|
could_alloc = True
|
||||||
# ifalloc = True
|
|
||||||
# for runtime_process in item["runtimeProcess"]:
|
for item in runtime_products_processes_list:
|
||||||
# runtime_process: runtime.RuntimeProcess = runtime_process
|
runtime_resource_needs: List[runtime.RuntimeResourceNeed] = []
|
||||||
# for resource_item in runtime_process.process.res_needs:
|
for runtime_process in item["runtimeProcess"]:
|
||||||
# resource_item['']
|
runtime_process: runtime.RuntimeProcess = runtime_process
|
||||||
# runtime_resource_need = runtime.RuntimeResourceNeed(runtime_process.process)
|
for resource_item in runtime_process.process.res_needs:
|
||||||
# if resource_pool.alloc_resource():
|
resource_attr = resource_item["rcs_attr"]
|
||||||
|
amount = resource_item["amount"]
|
||||||
|
for i in range(amount):
|
||||||
|
runtime_resource_need: runtime.RuntimeResourceNeed = runtime.RuntimeResourceNeed(
|
||||||
|
runtime_process,
|
||||||
|
resource_attr,
|
||||||
|
runtime_process.process.workspace,
|
||||||
|
start_time,
|
||||||
|
start_time + timedelta(minutes=runtime_process.process.pdt_time))
|
||||||
|
runtime_resource_needs.append(runtime_resource_need)
|
||||||
|
|
||||||
|
if resource_pool.try_alloc_resource(runtime_resource_needs):
|
||||||
|
resource_pool.alloc_resource(runtime_resource_needs)
|
||||||
|
else:
|
||||||
|
while resource_pool.reset_earliest_free_start_time(runtime_resource_needs):
|
||||||
|
resource_pool.try_alloc_resource(runtime_resource_needs)
|
||||||
|
resource_pool.alloc_resource(runtime_resource_needs)
|
||||||
|
|
||||||
|
for runtime_resource_need in runtime_resource_needs:
|
||||||
|
if runtime_resource_need.could_alloc is False:
|
||||||
|
could_alloc = False
|
||||||
|
break
|
||||||
|
|
||||||
|
return could_alloc
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
start_time: datetime = datetime.combine(date(2020, 8, 12), datetime.min.time())
|
||||||
|
|
||||||
m_orders, m_products, m_processes, m_resources = dataset_importer.import_dataset()
|
m_orders, m_products, m_processes, m_resources = dataset_importer.import_dataset()
|
||||||
|
resource_pool: runtime.RuntimeResourcePool = runtime.RuntimeResourcePool(m_resources.values(), start_time)
|
||||||
produce_list = orders_processor(m_orders)
|
produce_list = orders_processor(m_orders)
|
||||||
products_processor(produce_list)
|
rt_rcs_list = products_processor(produce_list)
|
||||||
|
print(resource_processor(rt_rcs_list, resource_pool, start_time))
|
||||||
|
Loading…
Reference in New Issue
Block a user