Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kan 18 feature prefer nearest deadline first #9

Merged
merged 19 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e84a261
chore(formatting code): clean optimize_order a little bit
ppaauuoo Aug 9, 2024
3d9ce2a
feat(file preview modal): working file preview on UI
ppaauuoo Aug 9, 2024
e1b556e
feat(UI): add loading mesage to the preview modal
ppaauuoo Aug 9, 2024
aa00ed7
Merge pull request #6 from ppaauuoo/KAN-9-data-preview-at-ui
ppaauuoo Aug 9, 2024
c6c68c1
feat(file preview): rework file preview to be full screen, and use ca…
ppaauuoo Aug 9, 2024
08d3214
feat(preview search): add search bar to the preview page
ppaauuoo Aug 9, 2024
deaab54
feat(order selector logic): ability to lock the input order to be in …
ppaauuoo Aug 9, 2024
a38eab0
feat(selector function on UI): first integration testing WIP
ppaauuoo Aug 9, 2024
9e2dd83
feat(out selector): working out for selected order from the selector …
ppaauuoo Aug 9, 2024
a882aad
feat(table sort): able to ascend and descend in the preview table
ppaauuoo Aug 10, 2024
67ccf5f
feat(order selector): order are selectable now
ppaauuoo Aug 10, 2024
efedaa2
feat(auto fucntion): optimizing auto function by useing cache system …
ppaauuoo Aug 10, 2024
8361ab5
Merge pull request #7 from ppaauuoo/KAN-23-feat-optimizing-auto-funct…
ppaauuoo Aug 10, 2024
34b333f
feat(manual selector): selected file in preview will appear as a resu…
ppaauuoo Aug 10, 2024
3093d37
feat(auto selector): selected order is now appear on auto optimizer
ppaauuoo Aug 10, 2024
4e7db1e
Merge pull request #8 from ppaauuoo/KAN-16-follow-order-function
ppaauuoo Aug 10, 2024
0357577
chore(formatting): rename , relocate a bunch of code. setup constant env
ppaauuoo Aug 10, 2024
f846ba9
fix(common trim): the old calculated is broken cause by the shift of …
ppaauuoo Aug 10, 2024
3b47c52
feat(closest deadline): add feature to beablle to expand itself if th…
ppaauuoo Aug 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified db.sqlite3
Binary file not shown.
8 changes: 8 additions & 0 deletions media/data/test_common_logic.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
5/1/2023,CM127,CM127,CM127,CM127,CM127,5,315,1120,295,0,0,12181125769,V,"1,200","1,320",0,FALSE,Y,A,FALSE,"1,320",0,10,26/04/23,11:27:35
5/1/2023,KB160,CM127,,,KB160,3,175,0,175,0,0,12181125780,U,"3,600","3,780","4,456",FALSE,Y,Y,FALSE,"3,780",0,5,26/04/23,11:04:34
5/1/2023,KB160,CM127,,,KB160,3,215,0,215,0,0,12181125634,U,710,780,0,FALSE,Y,A,FALSE,780,0,10,25/04/23,14:26:21
5/1/2023,KB160,CM127,CM127,CM127,KB160,5,232,0,232,0,0,12181125644,U,"6,920","7,260","3,626",FALSE,Y,A,FALSE,"7,260",0,5,25/04/23,14:25:48
5/1/2023,KB230,CM127,CM127,CM127,KB230,5,235,0,235,0,0,12181125628,U,"1,300","1,430",0,FALSE,Y,A,FALSE,"1,430",0,10,25/04/23,14:26:45
5/1/2023,KB230,CM127,CM127,CM127,KB230,5,260,0,260,0,0,12181125626,U,640,700,0,FALSE,Y,A,FALSE,700,0,10,25/04/23,14:26:51
5/1/2023,KS231,CM127,CM127,CM127,KB230,5,618,1580,162,194,162,12181125780,E,"3,600","3,780","3,700",FALSE,N,Y,FALSE,"3,780",0,5,26/04/23,11:04:34
5/1/2023,KS231,CM127,CM127,CM127,KB230,5,558,1196,139,280,139,12181125626,A,320,350,420,FALSE,N,Y,FALSE,350,0,10,25/04/23,14:26:51
118 changes: 118 additions & 0 deletions order_optimization/getter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from .modules.ordplan import ORD

from django.shortcuts import get_object_or_404

from .models import CSVFile

from typing import Dict, List, Tuple
from .modules.ga import GA
from django.core.cache import cache

from django.conf import settings

CACHE_TIMEOUT = settings.CACHE_TIMEOUT

def set_progress(progress) -> None:
cache.set("optimization_progress", progress, CACHE_TIMEOUT)

def get_selected_order(request)->Dict:
selector_id = request.POST.get("selector_id")
if selector_id:
selector_id = int(selector_id)
selector_out = int(request.POST.get("selector_out"))
return {
"order_id": selector_id,
"out": selector_out
}
return None


def get_genetic_algorithm(
request,
orders: ORD,
size_value: float,
out_range: int = 3,
num_generations: int = 50,
show_output: bool = False,
) -> GA:
"""
Run genetic algorithm optimization.

Args:
orders (ORD): The orders to optimize.
size_value (float): The size value for optimization.
out_range (int, optional): The out range parameter. Defaults to 3.
num_generations (int, optional): The number of generations to run. Defaults to 50.

Returns:
GA: The genetic algorithm instance after running optimization.
"""
cache.delete("optimization_progress")
ga_instance = GA(
orders,
size=size_value,
out_range=out_range,
num_generations=num_generations,
showOutput=show_output,
selector=get_selected_order(request)
)
ga_instance.get(set_progress=set_progress).run()

return ga_instance


def get_orders(
request,
file_id: str,
size_value: float,
deadline_scope: int = 0,
filter_value: int = 16,
tuning_values: int = 3,
filter: bool = True,
common: bool = False,
filler: int = 0,
) -> ORD:
"""
Get orders for optimization.

Args:
file_id (str): The ID of the CSV file.
size_value (float): The size value for optimization.
deadline_scope (int, optional): The deadline scope. Defaults to 0.
filter_value (int, optional): The filter value. Defaults to 16.
tuning_values (int, optional): The tuning values. Defaults to 3.
filter (bool, optional): Whether to apply filtering. Defaults to True.
common (bool, optional): Whether to use common optimization. Defaults to False.

Returns:
ORD: The ORD object with the retrieved orders.
"""
csv_file = get_object_or_404(CSVFile, id=file_id)
file_path = csv_file.file.path
return ORD(
path=file_path,
deadline_scope=deadline_scope,
filter=filter,
filter_value=filter_value,
size=size_value,
tuning_values=tuning_values,
common=common,
filler = filler,
selector = get_selected_order(request)
).get()

def get_outputs(ga_instance: GA) -> Tuple[float, List[Dict]]:
"""
Extract fitness values and output data from a GA instance.

Args:
ga_instance (GA): The Genetic Algorithm instance to extract data from.

Returns:
Tuple[float, List[Dict]]: A tuple containing:
- fitness_values (float): The fitness values from the GA instance.
- output_data (List[Dict]): The output data as a list of dictionaries.
"""
fitness_values = ga_instance.fitness_values
output_data = ga_instance.output.to_dict("records")
return fitness_values, output_data
191 changes: 191 additions & 0 deletions order_optimization/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
from .modules.ordplan import ORD

from typing import Callable, Dict
from django.contrib import messages
from django.core.cache import cache

import pandas as pd

from typing import Callable, Dict, List, Optional

from .getter import get_orders, get_outputs, get_genetic_algorithm

from django.conf import settings

ROLL_PAPER = settings.ROLL_PAPER
FILTER = settings.FILTER
OUT_RANGE = settings.OUT_RANGE
TUNING_VALUE = settings.TUNING_VALUE
CACHE_TIMEOUT = settings.CACHE_TIMEOUT

def handle_manual_config(request)->Callable:
file_id = request.POST.get("file_id")
size_value = int(request.POST.get("size_value"))
deadline_toggle = -1 if request.POST.get("deadline_toggle") == "true" else 0
filter_value = int(request.POST.get("filter_value"))
tuning_value = int(request.POST.get("tuning_value"))
num_generations = int(request.POST.get("num_generations"))
out_range = int(request.POST.get("out_range"))
orders = get_orders(request, file_id,size_value,deadline_toggle,filter_value,tuning_value)
if len(orders) <= 0:
messages.error(request, "Eror 404: No orders were found. Please try again.")
return
return handle_optimization(request, orders, num_generations, out_range, size_value)

def handle_auto_config(request)->Callable:
again = cache.get("try_again", 0)
num_generations = 50+(10*again)
out_range = 2+again
orders,size = size_filter_logic(request)
return handle_optimization(request, orders, num_generations, out_range, size)

def size_filter_logic(request):
i = 0
j = 7
orders = cache.get('auto_order', [])
size = cache.get('order_size', ROLL_PAPER[j])
file_id = request.POST.get("file_id")
tuning_value = TUNING_VALUE[1]
while len(orders) <= 0:
orders = get_orders(request, file_id,size,FILTER[-i],tuning_value)
i += 1
if i > len(FILTER):
i = 0
j+=1
size=ROLL_PAPER[j]

cache.set('auto_order', orders, CACHE_TIMEOUT)
cache.set('order_size', size, CACHE_TIMEOUT)

return (orders, size)

def handle_optimization(request, orders: ORD, num_generations: int, out_range: int, size_value: float)->Callable:
ga_instance = get_genetic_algorithm(request,orders, size_value, out_range, num_generations)
fitness_values, output_data = get_outputs(ga_instance)
init_order_number, foll_order_number = ORD.handle_orders_logic(output_data)
results = results_format(ga_instance, output_data, size_value, fitness_values, init_order_number, foll_order_number)

if abs(fitness_values) <= 3 and abs(fitness_values) >= 1:
messages.success(request, "Optimizing finished.")
return cache.set("optimization_results", results, CACHE_TIMEOUT)

again = cache.get("try_again", 0)

if "auto" in request.POST:
if again <= 4:
again+=1
cache.set("try_again", again, CACHE_TIMEOUT)
return handle_auto_config(request)
return messages.error(request, "Error : Auto config malfuncioned, please contact admin.")

satisfied = 1 if request.POST.get("satisfied") == "true" else 0
if satisfied:
if again <= 3:
again+=1
cache.set("try_again", again, CACHE_TIMEOUT)
return handle_optimization(request, orders, num_generations, out_range, size_value)

cache.delete("try_again")


messages.error(request, "Optimizing finished with unsatisfied result, please try again.")
return cache.set("optimization_results", results, CACHE_TIMEOUT)


def handle_common(request) -> Callable:
"""
Handle common order optimization.

Args:
request: The HTTP request object.
action: The action to perform ('trim' or 'order').

Returns:
Dict: The updated results dictionary.
"""
results = cache.get("optimization_results")
best_fitness = -results["trim"]
best_output: Optional[List[Dict]] = None
best_index: Optional[int] = None
file_id = request.POST.get("selected_file_id")


for i, item in enumerate(results["output"]):
size_value = (item["cut_width"]*item["out"]) + results["trim"]
orders = get_orders(request, file_id,size_value,deadline_scope=-1,tuning_values=3, filter=False,common=True)
ga_instance = get_genetic_algorithm(request,orders,size_value)


if abs(ga_instance.fitness_values) < abs(best_fitness):
best_fitness, best_output = get_outputs(ga_instance)
best_index = i

if best_index is not None:
update_results(results, best_index, best_output, best_fitness, size_value)
messages.success(request, "Common order found.")
else:
messages.error(request, "No suitable common order found.")

return cache.set("optimization_results", results, CACHE_TIMEOUT)

def update_results(results: Dict, best_index: int, best_output: List[Dict], best_fitness: float, size_value: float) -> None:
"""Update results with the best common order."""
old_order = results["output"][best_index]
results["output"].pop(best_index)
results["output"] = [item for item in results["output"] if item.get("out", 0) >= 1]
results["output"].extend(best_output)
results["fitness"] = (
( results["roll"] - (old_order["cut_width"]*old_order["out"]))
+ (best_fitness + size_value)
)
print("results['roll']:", results["roll"])
print("results['output'][best_index]['cut_width']:", results["output"][best_index]["cut_width"])
print("results['output'][best_index]['out']:", results["output"][best_index]["out"])
print("best_fitness:", best_fitness)
print("size_value:", size_value)
results["trim"] = abs(best_fitness)

def handle_filler(request):
results = cache.get("optimization_results")
init_order = results['output'][0]['order_number']
file_id = request.POST.get("selected_file_id")
size_value = results['output'][0]['cut_width']
init_out = results['output'][0]['out']
orders = get_orders(request, file_id,size_value,deadline_scope=-1,tuning_values=1, filter=False,common=True,filler=init_order)
i = 0
while i < len(orders) and results['foll_order_number'] > results['output'][1]['num_orders'] + orders['จำนวนสั่งขาย'][i]: i += 1

output = output_format(orders.iloc[i], init_out).to_dict(orient='records')
results['output'].extend(output)
return cache.set("optimization_results", results, CACHE_TIMEOUT)

def output_format(orders: ORD, init_out: int = 0) -> pd.DataFrame:
return pd.DataFrame(
{
"order_number": [orders["เลขที่ใบสั่งขาย"]],
"num_orders": [orders["จำนวนสั่งขาย"]],
"cut_width": [orders["กว้างผลิต"]],
"cut_len": [orders["ยาวผลิต"]],
"type": [orders["ประเภททับเส้น"]],
"deadline": [orders["กำหนดส่ง"]],
"out": [init_out],
}
)



def results_format(ga_instance: object, output_data: dict, size_value: int, fitness_values: float, init_order_number: int, foll_order_number: int) -> Dict:
return {
"output": output_data,
"roll": ga_instance.PAPER_SIZE,
"fitness": size_value + fitness_values,
"trim": abs(fitness_values),
"init_order_number": init_order_number,
"foll_order_number": foll_order_number
}






21 changes: 13 additions & 8 deletions order_optimization/modules/ga.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import numpy
import pandas as pd
from .ordplan import ORD

from typing import Dict
class GA:
def __init__(self, orders: ORD, size: float, num_generations: int, out_range: int,showOutput:bool = False, save_solutions:bool = False, showZero: bool = False)->None:
def __init__(self, orders: ORD, size: float, num_generations: int, out_range: int,showOutput:bool = False, save_solutions:bool = False, showZero: bool = False, selector: Dict = None)->None:
self.orders = orders
self.PAPER_SIZE = size
self.showOutput = showOutput
self.save_solutions = save_solutions
self.showZero = showZero
self.selector = selector

self.num_generations = num_generations
# num_parents_mating = len(orders)
Expand Down Expand Up @@ -59,8 +60,7 @@ def __init__(self, orders: ORD, size: float, num_generations: int, out_range: in
)

self.current_generation = 0



def paper_type_logic(self, solution):
init_type = None
orders = self.orders
Expand Down Expand Up @@ -108,10 +108,15 @@ def fitness_function(self, ga_instance, solution, solution_idx):
self.penalty = 0
self.penalty_value = 1000

if self.selector:
solution[0]=self.selector['out']

self.paper_type_logic(solution)

self.paper_out_logic(solution)



output = numpy.sum(solution * self.orders["กว้างผลิต"]) # ผลรวมของตัดกว้างทั้งหมด
self.paper_size_logic(output)

Expand All @@ -123,9 +128,9 @@ def fitness_function(self, ga_instance, solution, solution_idx):
def on_gen(self, ga_instance):

self.current_generation += 1
if self.update_progress:
if self.set_progress:
progress = (self.current_generation / self.num_generations) * 100
self.update_progress(progress)
self.set_progress(progress)

orders = self.orders

Expand Down Expand Up @@ -173,6 +178,6 @@ def show(self, ga_instance, output):
print("Trim :", abs(self.fitness_values))
print("\n")

def get(self, update_progress):
self.update_progress= update_progress
def get(self, set_progress):
self.set_progress= set_progress
return self.model
Loading
Loading