Skip to content

Commit

Permalink
Remove explicit threading, simplifying code
Browse files Browse the repository at this point in the history
  • Loading branch information
tungufoss committed Jan 15, 2024
1 parent 456c50a commit 71a5f6a
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 27 deletions.
13 changes: 4 additions & 9 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
from config.settings import GlulamConfig
from utils.logger import setup_logger
import os
from multiprocessing import cpu_count


def main(file_path, depth, name, run, mode, overwrite, num_cpus):
def main(file_path, depth, name, run, mode, overwrite):
logger = setup_logger('IDeLM-Glulam')
logger.info("Starting the Glulam Production Optimizer")

Expand All @@ -34,13 +33,13 @@ def main(file_path, depth, name, run, mode, overwrite, num_cpus):

if mode == "ES":
# Evolutionary Search mode
evolution_strategy = EvolutionStrategy(data, max_generations=GlulamConfig.ES_MAX_GENERATIONS, num_cpus=num_cpus)
evolution_strategy = EvolutionStrategy(data, max_generations=GlulamConfig.ES_MAX_GENERATIONS)
evolution_strategy.Search(filename)

elif mode == "single":
wr = [22800, 23000, 23500, 23600, 23700, 24900]
logger.info(f"Running a single run mode with width: {wr} roll widths")
evolution_strategy = EvolutionStrategy(data, max_generations=2, num_cpus=num_cpus)
evolution_strategy = EvolutionStrategy(data, max_generations=2)
evolution_strategy.Search(filename, x=wr)
else:
logger.error(f"Unknown mode: {mode}")
Expand Down Expand Up @@ -74,10 +73,6 @@ def main(file_path, depth, name, run, mode, overwrite, num_cpus):
"--overwrite", action="store_true", default=False,
help="Overwrite existing files (default: %(default)s)"
)
parser.add_argument(
'--num_cpus', type=int, default=cpu_count(),
help="Threads to be used in Gurobi (default: %(default)s)"
)
args = parser.parse_args()

main(args.file, args.depth, args.name, args.run, args.mode, args.overwrite, args.num_cpus)
main(args.file, args.depth, args.name, args.run, args.mode, args.overwrite)
16 changes: 5 additions & 11 deletions models/cutting_pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,16 @@


class GlulamPatternProcessor:
def __init__(self, data, num_cpus, roll_width=GlulamConfig.MAX_ROLL_WIDTH):
def __init__(self, data, roll_width=GlulamConfig.MAX_ROLL_WIDTH):
"""
Initializes the GlulamPatternProcessor with the necessary data.
Parameters:
- data (GlulamDataProcessor): An instance of the GlulamDataProcessor class, which contains the glulam data.
- num_cpus (int): How many cpus can be used in the cutting stock optimisation.
- roll_width (float, optional): The maximum width available on the roll. Defaults to the value in GlulamConfig.
"""
self.data = data

self.num_cpus = num_cpus

self.roll_width = roll_width
assert roll_width <= GlulamConfig.MAX_ROLL_WIDTH, (f"Roll width {roll_width} mm exceeds the maximum roll "
f"width {GlulamConfig.MAX_ROLL_WIDTH} mm.")
Expand Down Expand Up @@ -132,8 +129,7 @@ def cutting_stock_column_generation(self):
while not bailout:
# Create the cutting model
cut_model = gp.Model("Cutting")
cut_model.setParam('OutputFlag', 0)
cut_model.setParam('Threads', self.num_cpus)
cut_model.setParam('OutputFlag', 0) # Suppress output for cleaner execution

# Decision variables: how often to cut each pattern
x = cut_model.addVars(self.J) # Note this a continuous variable in order to get shadow prices later
Expand Down Expand Up @@ -181,7 +177,6 @@ def _column_generation_subproblem(self, pi):
# Initialize the knapsack model
knap_model = gp.Model("Knapsack")
knap_model.setParam('OutputFlag', 0) # Suppress output for cleaner execution
knap_model.setParam('Threads', self.num_cpus)

# Decision variables for the knapsack problem
use = knap_model.addVars(self.I, lb=0, vtype=gp.GRB.INTEGER)
Expand Down Expand Up @@ -259,15 +254,14 @@ def _remove_duplicate_patterns(self):


class ExtendedGlulamPatternProcessor(GlulamPatternProcessor):
def __init__(self, data, num_cpus):
def __init__(self, data):
"""
Initializes the ExtendedGlulamPatternProcessor with the necessary data.
Parameters:
- data (GlulamDataProcessor): An instance of the GlulamDataProcessor class, which contains the glulam data.
- num_cpus (int): Number of cpus that can be used in cutting stock optimisation.
"""
super().__init__(data, num_cpus) # Initialize the base class
super().__init__(data) # Initialize the base class
self._roll_widths = set()

# Calculate the minimum number of presses needed to pack all orders
Expand Down Expand Up @@ -303,7 +297,7 @@ def add_roll_width(self, roll_width):
merged_logger.info(f"Roll width {roll_width} already exists in the existing patterns, n={self.n}.")
return

pattern = GlulamPatternProcessor(self.data, self.num_cpus, roll_width=roll_width)
pattern = GlulamPatternProcessor(self.data, roll_width=roll_width)
pattern.cutting_stock_column_generation()
self._A = np.hstack((self._A, pattern.A))
self._H = np.concatenate((self._H, pattern.H))
Expand Down
4 changes: 2 additions & 2 deletions models/pack_n_press.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ def cb(model, where):
model._terminated_early = time.time()
model.terminate()
logger.warning(f"Terminating optimization: no improvement for over "
f"{GlulamConfig.GUROBI_NO_IMPROVEMENT_TIME_LIMIT/60:.0f} minute. "
f"{GlulamConfig.GUROBI_NO_IMPROVEMENT_TIME_LIMIT / 60:.0f} minute. "
f"Elapsed time since first feasible solution: "
f"{(model._terminated_early - model._feasible_time) / 60:.2f} minutes.")


class GlulamPackagingProcessor:
def __init__(self, pattern_processor, number_of_presses, number_of_regions=GlulamConfig.REGIONS):
"""
Expand Down Expand Up @@ -195,7 +196,6 @@ def pack_n_press(self, time_limit=GlulamConfig.GUROBI_TIME_LIMIT):

# Set time limit
pmodel.setParam('TimeLimit', time_limit)
pmodel.setParam('Threads', self.patterns.num_cpus)

# decision variables
x = pmodel.addVars(self.J, self.K, self.R, vtype=gp.GRB.INTEGER)
Expand Down
9 changes: 4 additions & 5 deletions strategies/evolution_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
class EvolutionStrategy:
""" Evolution Strategy class based on the (1+1)-ES algorithm """

def __init__(self, data, num_cpus,
max_generations=None, alpha=0.1, sigma0=5, lamda=10, n_max=None, dn=None, n_min=0):
def __init__(self, data, max_generations=None, alpha=0.1, sigma0=5, lamda=10, n_max=None, dn=None, n_min=0):
self.max_generations = max_generations or GlulamConfig.ES_MAX_GENERATIONS
""" Maximum number of generations to be used in the search. """

Expand All @@ -44,7 +43,7 @@ def __init__(self, data, num_cpus,
""" Statistics of the search. """

# generate packing patterns from input data
self.merged = ExtendedGlulamPatternProcessor(data, num_cpus)
self.merged = ExtendedGlulamPatternProcessor(data)
""" The merged pattern processor. """

self.npresses = None
Expand Down Expand Up @@ -232,7 +231,7 @@ def save_results(filename):
self.Selection(x, sigma, success, press)

# now lets start the search, for max max_generations
self._add_stats(x, sigma, 0,(self.waste, self.npresses))
self._add_stats(x, sigma, 0, (self.waste, self.npresses))
for gen in range(1, self.max_generations):
logger.info(f"Generation: {gen}/{self.max_generations}")

Expand Down Expand Up @@ -291,7 +290,7 @@ def save_results(filename):
logger.info(f"NEW BEST: the number of patterns is {self.merged.n}")

self._add_stats(x, sigma, gen, (waste_, npresses_))
save_results(filename+".part")
save_results(filename + ".part")

logger.info(f"Search - Finished the search after {self.max_generations} generations.")

Expand Down

0 comments on commit 71a5f6a

Please sign in to comment.