simpy 仿真模拟 2个资源

simpy 仿真 模拟

一个车间内有100台相同的机器,每台机器正常运行时每小时能固定创造3元的净利润,但平均每小时损坏一次。而一个熟练修理工修复一台机器平均需0.5小时,一个不熟练修理工修复一台机器平均需3小时。以上时间均服从指数分布。设一名熟练修理工一小时工资为6元,一名不熟练修理工一小时工资为2元。车间每天工作8小时。试求该车间应设多少名熟练修理工和不熟练修理工,使每周(6天)的总净利润最大?

import numpy as np
from sko.GA import GA
import pandas as pd
import matplotlib.pyplot as plt
import random
import simpy
Days= 10             # Simulation time in weeks
RANDOM_SEED = 42
PT_MEAN = 10.0         # Avg. processing time in minutes
PT_SIGMA = 2.0         # Sigma of processing time
MTTF = 60           # Mean time to failure in minutes
BREAK_MEAN = 0.017 # Param. for expovariate distribution
REPAIR_WAGE1 = 0*6 * 8 * Days # 第一种修理工的小时工资
REPAIR_WAGE2 = 0 *2 * 8 * Days # 第二种修理工的小时工资
REPAIR_TIME1 = 30.0     # 第一种修理工修理一台机器所需时间(分钟)
REPAIR_TIME2 = 180.0    # 第二种修理工修理一台机器所需时间(分钟)
JOB_DURATION = 10    # Duration of other jobs in minutes
NUM_MACHINES = 10    # Number of machines in the machine shop
SIM_TIME =8*60*Days # Simulation time in minutes


def time_per_part():
    """Return actual processing time for a concrete part."""
    return 60


def time_to_failure():
    """Return time until next failure for a machine."""
    return random.expovariate(BREAK_MEAN)


def time_per_part():
    """Return actual processing time for a concrete part."""
    return 60


def time_to_failure():
    """Return time until next failure for a machine."""
    return random.expovariate(BREAK_MEAN)


class Machine(object):
    def __init__(self, env, name, repairman1,repairman2):
        self.env = env
        self.name = name
        self.parts_made = 0
        self.broken = False
        self.process = env.process(self.working(repairman1,repairman2))
        env.process(self.break_machine())


    def working(self, repairman1, repairman2):
        """Produce parts as long as the simulation runs.

        While making a part, the machine may break multiple times.
        Request a repairman when this happens.

        """
        while True:
            # Start making a new part
            done_in = time_per_part()
            while done_in:
                try:
                    # Working on the part
                    start = self.env.now
                    yield self.env.timeout(done_in)
                    done_in = 0  # Set to 0 to exit while loop.
                except simpy.Interrupt as interrupt:
                    self.broken = True
                    done_in -= self.env.now - start  # How much time left?
                    # Ignore the interrupt and continue with the next iteration

                    # Handle multiple interrupts
                    while isinstance(interrupt.cause, simpy.Interrupt):
                        interrupt = interrupt.cause

                if self.broken:  # Add this condition to skip repair process
                    continue

                # Request a repairman. This will preempt its "other_job".
                if not repairman1.count - repairman1.capacity == 0:
                    with repairman1.request(priority=1) as req:
                        yield req
                        yield self.env.timeout(REPAIR_TIME1)
                        self.broken = False
                else:
                    with repairman2.request(priority=1) as req:
                        yield req
                        yield self.env.timeout(REPAIR_TIME2)
                        self.broken = False

            # Part is done.
            self.parts_made += 1

    def break_machine(self):
        """Break the machine every now and then."""
        while True:
            yield self.env.timeout(time_to_failure())
            if not self.broken:
                # Only break the machine if it is currently working.
                self.process.interrupt()
def other_jobs(env, repairman1,repairman2):
    while True:
        done_in = JOB_DURATION
        while done_in:
            with repairman1.request(priority=2) as req:
                yield req
                try:
                    start = env.now
                    yield env.timeout(done_in)
                    done_in = 0
                except simpy.Interrupt:
                    done_in -= env.now - start
            with repairman2.request(priority=2) as req:
                yield req
                try:
                    start = env.now
                    yield env.timeout(done_in)
                    done_in = 0
                except simpy.Interrupt:
                    done_in -= env.now - start

        
def problem(parameter):
    random.seed(RANDOM_SEED)  # This helps reproducing the result
    x1,x2= parameter  # 将参数赋值给 x1 和 x2

    env = simpy.Environment()  # 创建环境对象
    repairman1 = simpy.PreemptiveResource(env, capacity=x1) 
    repairman2 = simpy.PreemptiveResource(env, capacity=x2)
    machines = [Machine(env, 'Machine %d' % i, repairman1,repairman2) for i in range(NUM_MACHINES)]
    env.process(other_jobs(env, repairman1,repairman2))
    env.run(until=SIM_TIME)
    for machine in machines:
        print('%s made %d parts.' % (machine.name, machine.parts_made))
    money = 0
    for machine in machines:
        money += machine.parts_made * 3
    money -= (x1  *REPAIR_WAGE1)  # 第一种修理工的工资
    money -= (x2  *REPAIR_WAGE2)  # 第二种修理工

    return money
print(problem([100,100]))
# problem_dimension = 2  # 两种修理工 # 每种修理工的数量范围
# # 使用遗传算法求解问题
# ga = GA(func=problem, n_dim=problem_dimension, size_pop=50, max_iter=100, lb=[1,1], ub=[10,10],precision=1)
# best_solution, best_fitness = ga.run()

# print("Best solution:", best_solution)
# print("Best fitness:", best_fitness)




# Y_history = pd.DataFrame(ga.all_history_Y)
# fig, ax = plt.subplots(2, 1)
# ax[0].plot(Y_history.index, Y_history.values, '.', color='red')
# Y_history.min(axis=1).cummin().plot(kind='line')
# plt.show()



不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这有个类似的问题, 你可以参考下: https://ask.csdn.net/questions/7796083
  • 除此之外, 这篇博客: 机器学习-过拟合、正则化、稀疏性、交叉验证概述中的   剪枝是决策树中一种控制过拟合的方法,我们知道决策树是一种非常容易陷入过拟合的算法,剪枝处理主要有预剪枝和后剪枝这两种,常见的是两种方法一起使用。预剪枝通过在训练过程中控制树深、叶子节点数、叶子节点中样本的个数等来控制树的复杂度。后剪枝则是在训练好树模型之后,采用交叉验证的方式进行剪枝以找到最优的树模型。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:
  • 以下回答来自chatgpt:

    首先,我们需要确定应该雇佣多少名熟练修理工和不熟练修理工来实现最优解。

    假设我们雇佣a名熟练修理工和b名不熟练修理工。

    根据题目中的条件,我们可以计算出每天机器的平均损坏次数,即100台机器每天平均损坏100次。 修理一台机器平均需要0.5小时的时间,其中熟练修理工和不熟练修理工的修理时间分别为0.5小时和3小时。修理时间服从指数分布。

    我们需要计算出不同修理工的修理效率和工资开支,以及每周的总净利润。

    首先计算不同修理工的修理效率: - 熟练修理工的修理效率 = 修理工每小时的工作时间 / 修理时间 - 不熟练修理工的修理效率 = 修理工每小时的工作时间 / 修理时间

    然后计算不同修理工的工资开支: - 熟练修理工的工资开支 = 熟练修理工的小时工资 * 熟练修理工的工作时间 - 不熟练修理工的工资开支 = 不熟练修理工的小时工资 * 不熟练修理工的工作时间

    工作时间 = 每天的工作小时数 * 每周的工作天数 = 8 * 6 = 48小时

    工作效率和工资开支计算完毕后,我们可以计算每周的总净利润: 总净利润 = 每天机器的净利润 * 每台机器的正常运行小时数 - 工资开支

    每天机器的净利润 = 每台机器正常运行小时数 * 每小时的净利润 = 3元 每台机器正常运行小时数 = 每天的工作小时数 - 平均每台机器的损坏次数 * 平均修理时间 平均每台机器的损坏次数 = 每台机器的正常运行小时数 / 平均修理时间

    将上述公式代入,可以得到总净利润的表达式。 用a和b来表示雇佣的熟练修理工和不熟练修理工的数量,我们的目标是使总净利润最大化。

    提出问题时并没有给出任何限制条件,因此我们需要进行进一步的假设和限制条件,以便能够得出具体的解决方案。

    由于题目没有给出修理时间服从指数分布的具体参数,我们可以假设修理时间服从指数分布的参数为1,这样方便我们进行计算和模拟。

    在这个假设下,我们可以编写代码来模拟雇佣不同数量的熟练修理工和不熟练修理工的情况,计算总净利润,并找到最优解。

    以下是具体的解决方案的伪代码:

    ```python

    雇佣不同数量的熟练修理工和不熟练修理工的模拟

    best_profit = 0 # 最大的总净利润 best_a = 0 # 最优解对应的熟练修理工数量 best_b = 0 # 最优解对应的不熟练修理工数量

    for a in range(1, 100): # 遍历熟练修理工数量 for b in range(1, 100): # 遍历不熟练修理工数量 # 计算熟练修理工和不熟练修理工的工作效率 proficient_efficiency = 0.5 / 0.5 # 熟练修理工的工作效率 unskilled_efficiency = 0.5 / 3 # 不熟练修理工的工作效率

        # 计算熟练修理工和不熟练修理工的工资开支
        proficient_salary = 6 * 48 * a  # 熟练修理工的工资开支
        unskilled_salary = 2 * 48 * b  # 不熟练修理工的工资开支
    
        # 计算每周的总净利润
        daily_profit = 3
        normal_hours = 8 - 1  # 每台机器正常运行的小时数,减去平均每台机器的损坏次数
        average_repair_time = 0.5  # 平均修理时间,假设为0.5小时
        average_damage_times = normal_hours / average_repair_time  # 平均每台机器的损坏次数
        normal_hours = normal_hours * 100  # 将小时转换为分钟,为了模拟修理时间服从指数分布
        total_profit = 0  # 每周的总净利润
    
        # 模拟每天的损坏和修理过程
        for day in range(6):  # 模拟6        for machine in range(100):  # 100台机器
                for repair_time in range(int(average_damage_times * 60) + 1):  # 每台机器需要的修理时间
                    # 使用指数分布模拟修理时间
                    repair_time = -math.log(random.random()) * repair_time
                    if repair_time <= normal_hours:
                        # 机器正常运行时的净利润
                        total_profit += daily_profit
                    else:
                        # 使用熟练修理工还是不熟练修理工修理机
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^