debug和rlease的区别

在使用VC开发软件的过程中,正当要享受那种兴奋的时候突然发现:release与debug运行结果不一致,甚至出错,而release又不方便调试,真的是当头一棒啊,可是疼归疼,问题总要解决,下面将讲述一下我的几点经验,看看是不是其中之一:


1. 变量。
 大家都知道,debug跟release在初始化变量时所做的操作是不同的,debug是将每个字节位都赋成0xcc(注1),而release的赋值近似于随机(我想是直接从内存中分配的,没有初始化过)。这样就明确了,如果你的程序中的某个变量没被初始化就被引用,就很有可能出现异常:用作控制变量将导致流程导向不一致;用作数组下标将会使程序崩溃;更加可能是造成其他变量的不准确而引起其他的错误。所以在声明变量后马上对其初始化一个默认的值是最简单有效的办法,否则项目大了你找都没地方找。代码存在错误在debug方式下可能会忽略而不被察觉到,如debug方式下数组越界也大多不会出错,在release中就暴露出来了,这个找起来就比较难了:( 还是自己多加注意吧

2. 自定义消息的消息参数。
 MFC为我们提供了很好的消息机制,更增加了自定义消息,好处我就不用多说了。这也存在debug跟release的问题吗?答案是肯定的。在自定义消息的函数体声明时,时常会看到这样的写法:afx_msg LRESULT OnMessageOwn(); Debug情况下一般不会有任何问题,而当你在Release下且多线程或进程间使用了消息传递时就会导致无效句柄之类的错误。导致这个错误直接原因是消息体的参数没有添加,即应该写成:afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam); (注2)

3. release模式下不出错,但debug模式下报错。
 这种情况下大多也是因为代码书写不正确引起的,查看MFC的源码,可以发现好多ASSERT的语句(断言),这个宏只是在debug模式下才有效,那么就清楚了,release版不报错是忽略了错误而不是没有错误,这可能存在很大的隐患,因为是Debug模式下,比较方便调试,好好的检查自己的代码,再此就不多说了。

4. ASSERT, VERIFY, TRACE..........调试宏
这种情况很容易解释。举个例子:请在VC下输入ASSERT然后选中按F12跳到宏定义的地方,这里你就能够发现Debug中ASSERT要执行AfxAssertFailedLine,而Release下的宏定义却为"#define ASSERT(f) ((void)0)"。所以注意在这些调试宏的语句不要用程序相关变量如i++写操作的语句。VERIFY是个例外,"#define VERIFY(f) ((void)(f))",即执行,这里的作用就不多追究了,有兴趣可自己研究:)。


总结:
 Debug与Release不同的问题在刚开始编写代码时会经常发生,99%是因为你的代码书写错误而导致的,所以不要动不动就说系统问题或编译器问题,努力找找自己的原因才是根本。我从前就常常遇到这情况,经历过一次次的教训后我就开始注意了,现在我所写过的代码我已经好久没遇到这种问题了。下面是几个避免的方面,即使没有这种问题也应注意一下:

1. 注意变量的初始化,尤其是指针变量,数组变量的初始化(很大的情况下另作考虑了)。
2. 自定义消息及其他声明的标准写法
3. 使用调试宏时使用后最好注释掉
4. 尽量使用try - catch(...)
5. 尽量使用模块,不但表达清楚而且方便调试。

注1:
afc(afc) 网友提供:
 debug版初始化成0xcc是因为0xcc在x86下是一条int 3单步中断指令,这样程序如果跑飞了遇到0xcc就会停下来,这和单片机编程时一般将没用的代码空间填入jmp 0000语句是一样地

注2:
 不知大家有没有遇到过这种情况,具体原因我也不太清楚,是不是调用时按着默认的参数多分配了WPARAM+LPARAM的空间而破坏了应用程序的内存空间?还请高手来补充。

NightWolf 网友提供:我遇见过,好像是在函数调用的时候参数入栈的问题。因为MFC的消息使用宏写的,所以如果定义了OnMessage()的函数,编译能够通过,但是调用一次后,堆栈指针发生了偏移。然后就。。。

 

1. 符号说明: 集合 L LOT集合 M Machine集合 O Step集合 参数 l Lot l m_o 第o道工序的Machine m m_Last 最后一道工序的Machine m o_l Lot l 的工序 o_Last Lot l 的最后一道工序 〖QTY〗_l Lot l 的wafer qty 〖WPH〗_Om 第o道工序的Machine m的WPH K_lom Lot l 的第o道工序是否可以在machine m上加工 C_m Machine m 的Capability/Uptime t_lo Lot l 在第o step的buffer time + transfer time p_lo Lot l 在第o step的process time r_l Lot l 的release time 〖RQT〗_l LOT l release时身上剩余的Qtime 〖QT〗_(loo^· ) Lot l 在第o step到第o· step的Q time 〖qt〗_(loo^· ) Lot l 在第o step到第o· step是否有Q time N 一个正无穷大的数 〖SD_PM〗_(mtt^· ) Machine m 在t到t·时间SD_PM r_m Machine m 的release time 中间变量 Cmax 所有lot的完工时间最大化 〖UT〗_(Last m) 最后一道工序的machine m的UT 〖QT〗_(l(O,o^·)) Lot l 是否在第o-->o^· 道工序over Qtime,0-1变量 QTmax 所有over Q time的lot数量 〖CT〗_l Lot l 的cycle time CTmax 所有lot的cycle time 〖MOVEmax〗_(Last m) 每个机台的move最大化 s_lo Lot l 在第o step的start time e_lo Lot l 在第o step的end time 决策变量 x_lom Lot l 的第o道工序是否在machine m上加工,0-1变量 x_(l Last m) Lot l的最后一道工序是否在machine m上加工 2. 目标函数: min⁡(Cmax,〖−UT〗_(Last m),QTmax,−MOVEmax,CTmax) 3. 约束条件: ∑8_(o∈O,m∈M)▒〖x_lom×K_lom=1〗,∀l∈L (1) lot的每道工序只能在一个机台上加工; p_lo=〖WPH〗_Om×〖QTY〗_l,∀l∈L,o∈O,m∈M(2) lot在每个工序机台上的加工时间; ∑8_(l∈L)▒〖x_lom×p_lo≤C_m 〗,∀o∈O,m∈M(3) 每道工序对应机台的capability限制; r_(l ) 〖<s〗_l1,∀l∈L (4) LOT 到站后才能上机台; r_m<s_l1,∀l∈L,m∈M(5) 机台可用后lot才能上机台; s_lo+p_lo+t_l(o+1) ≤s_l(o+1) ,∀l∈L,o∈O(6) lot在上一站机台加工完才能进入下一站的机台; s_l1−r_(l )≤〖RQT〗_l (7) lot刚rlease上机台时不over Qtime; s_l(o+1) −(s_lo+p_lo )≤〖QT〗_lo(o+1) ,∀l∈L,o∈O(8) lot上机台时不over Qtime; 〖QT〗_lo(o+1) −s_l(o+1) +e_lo≤N(〖1−QT〗_lo )(9) 〖QT〗_lo(o+1) −s_l(o+1) +e_lo≥−N〖·QT〗_lo (10) Lot 是否在第o道工序 over Q time,若over记1,反之记0; 〖CT〗_l=∑8_(o∈o_Last)▒(e_lo−r_(l ) ) (11) Lot的cycle time; Cmax=∑8_(l∈L)▒∑8_(o∈o_Last)▒e_lo (12) 所有lot的总加工时间 QTmax=∑8_(l∈L)▒〖QT〗_(l(O,o^·)) (13) 所有lot over Qtime的个数 CTmax=∑8_(l∈L)▒〖CT〗_l (14) 所有lot的cycle time 〖UT〗_(Last m)=∑8_(l∈L)▒∑8_(o∈o_Last)▒〖x_lom×p_lo 〗 〖/C〗_(Last m) (15) 最后一道工序机台的UT 〖MOVEmax〗_(Last m)=∑8_(l∈L)▒∑8_(o∈o_Last)▒〖x_lom×〖QTY〗_l 〗(16) 最后一道工序机台的move 上述MIP模型若用python调用ortools求解器的求解代码是什么,能否可以运行成功,输入简单的数据,运行出结果,并将结果输出一个可视化的甘特图
最新发布
03-11
<think>好的,我现在要帮用户解决一个关于使用Python调用OR-Tools求解器来实现他们提供的MIP模型的问题,并且还要生成可视化的甘特图。首先,我需要仔细理解用户提供的模型结构要求。 首先,用户给出了详细的符号说明、目标函数、约束条件。他们的模型涉及多个目标的最小化,包括Cmax(总完工时间最大化)、UT的负数(最大化最后一道工序机器的利用率)、QTmax(超过Q时间的lot数量)、MOVEmax的负数(最大化最后工序机器的移动次数)、以及CTmax(总周期时间)。这是一个多目标优化问题,可能需要通过加权或其他方法转换为单目标,或者使用多目标优化技术,但OR-Tools的MIP求解器可能更适用于单目标,所以可能需要用户选择主要目标或组合目标。 接下来,用户希望得到Python代码,使用OR-Tools,输入简单数据后能运行成功,并输出甘特图。因此,我需要考虑以下几点: 1. **模型转化**:将给定的约束条件目标函数转化为OR-Tools的变量约束。注意到OR-Tools的线性求解器支持MIP,但多目标可能需要处理,比如将多个目标加权求,或者分优先级。 2. **变量定义**:用户模型中涉及的决策变量主要是x_lom(0-1变量),表示工序分配。此外还有时间变量如s_lo(开始时间)、e_lo(结束时间)等。但OR-Tools中处理时间变量可能需要使用整数变量,或者通过约束来连接这些变量。 3. **约束条件实现**:需要逐一将每个约束转化为代码。例如,约束(1)每个工序只能分配到一个机器,这可以通过sum(x_lom * K_lom) = 1来实现。但需要处理不同l, o的组合。 4. **目标函数整合**:由于OR-Tools的求解器通常处理单目标,可能需要将多个目标合并。例如,给每个目标赋予权重,或者选择其中一个作为主要目标,其他作为约束。但用户提供的目标函数是min(Cmax, -UT_Last m, QTmax, -MOVEmax, CTmax),即同时最小化多个目标,这可能需要多目标优化方法。不过OR-Tools的MIP求解器可能不支持直接多目标,所以可能需要用户权衡,或者选择其中一个作为目标,其他作为约束。 5. **输入数据准备**:用户要求输入简单的数据,因此需要构造一个小规模的测试案例,包含几个Lot、Machine、Step,参数如QTY、WPH、K_lom等。 6. **结果的可视化**:生成甘特图,可能需要使用matplotlib或其他库,将每个Lot在各工序的开始结束时间在对应的机器上绘制出来。 接下来,逐步分析各个部分: 首先,用户模型中变量较多,需要确定哪些是决策变量,哪些是中间变量。决策变量主要是x_lom,而时间变量如s_lo、e_lo可能由x_lom其他参数决定,但需要根据约束条件来建立它们之间的关系。 例如,约束(6)是s_lo + p_lo + t_l(o+1) ≤ s_l(o+1),这意味着每个Lot的下一工序的开始时间必须大于等于当前工序的结束时间加上传输时间。这可能需要用线性约束来连接这些变量。 但OR-Tools中的变量需要明确声明,例如,s_loe_lo可能需要定义为连续变量或者整数变量。对于每个Lot每个工序,这些变量需要存在,不管是否分配到某个机器。或者,是否只有当x_lom=1时,这些变量才被激活? 这可能比较复杂,因为每个工序的加工时间p_lo是根据机器m的WPHQTY决定的。例如,p_lo = QTY_l / WPH_Om(假设WPH是每小时处理量,所以时间=数量/速率)。但根据用户给出的参数p_lo的定义,它其实是对于每个l, o, m的组合计算的,而x_lom决定是否选择这个m。因此,实际的加工时间p_lo可能只有在x_lom=1时才等于QTY_l / WPH_Om,否则可能不适用。但用户将p_lo定义为参数,这可能意味着对于每个lo,已经预先计算了在所有可能机器上的p_lo,而x_lom决定选择哪个机器的p_lo。但约束(2)中p_lo = WPH_Om * QTY_l,这可能存在笔误,因为通常加工时间应该是数量除以速率(即QTY / WPH),所以可能需要确认。假设用户是正确的,即p_lo是WPH乘以QTY,那这可能意味着处理时间更长,这可能不符合现实,但按照模型定义来编码。 接下来,约束(3)是每个机器在每道工序上的总加工时间不超过其能力C_m。这需要对于每个om,sum(x_lom * p_lo) ≤ C_m。但p_lo在这里是当x_lom=1时的处理时间,所以这需要正确计算。 另一个复杂点是时间约束。例如,约束(4)(5)要求s_l1(第一个工序的开始时间)必须大于r_l(release time)机器的release time r_m。这需要将s_l1设置为大于这两个时间中的最大值。但如何用线性约束表示最大值?可能需要分开处理,比如s_l1 >= r_l s_l1 >= r_m。但约束(4)(5)分别写成了r_l < s_l1r_m < s_l1,所以可能需要转换为s_l1 >= r_l +1 或类似的,但具体是否允许等于要看用户意图。但原约束是严格小于,这在MIP模型中通常用<=表示,因为时间可能是连续或离散的。这里可能需要调整,比如s_l1 >= r_l + epsilon,但可能用户的实际模型中是大于等于,这里可能存在输入错误,需要确认。但为了简化,可以假设原约束应为s_l1 >= r_l s_l1 >= r_m。 接下来,处理时间约束时,必须确保每个工序的开始结束时间正确。例如,e_lo = s_lo + p_lo,其中p_lo是根据所选机器的处理时间。但p_lo是参数,对于每个l, o, m,当x_lom=1时,p_lo是固定的。因此,需要将s_loe_lo与x_lom相关联。但如何在OR-Tools中处理这样的条件约束? 这里可能需要使用大M法。例如,如果x_lom=1,则s_loe_lo必须满足e_lo = s_lo + p_lo,否则可能不需要。但实际情况是,每个工序必须被分配到一台机器,因此对于每个lo,必须有一个m使得x_lom=1,并且此时e_lo = s_lo + p_lo(对应所选m的p_lo)。因此,可能需要将p_lo分解为每个可能的m的处理时间,并使用x_lom来决定哪一个被采用。 但这样处理起来比较复杂,因为每个lo的p_lo的值取决于所选的m。例如,假设对于工序o,机器m的处理时间p_lom = QTY_l / WPH_Om(这里假设用户可能有误,正确应为时间=数量/每小时处理量),但用户给出的约束(2)是p_lo = WPH_Om * QTY_l,这可能有问题,需要检查。例如,如果WPH是每小时处理量,那么处理时间应该是数量除以WPH,即p = QTY / WPH。例如,QTY=10,WPH=5,则时间=2小时。但如果用户写成乘法,可能处理时间的计算是错误的,但根据用户提供的约束,必须按此处理,所以可能需要按照给定的公式p_lo = WPH_Om * QTY_l来编码,这可能意味着处理时间与机器速度成正比,这似乎不符合常理,但必须按照用户给出的模型来处理。 这可能是一个笔误,但在代码中需要按照用户的定义来执行。因此,在输入数据时,需要注意这一点,可能需要调整测试数据中的参数,以符合这个公式。 回到时间变量的处理。例如,对于每个lo,e_lo应该等于s_lo加上对应机器的处理时间。但由于每个工序只能选一个机器,所以需要建立约束:e_lo = s_lo + sum_{m} (x_lom * p_lom),其中p_lom是当工序o在机器m上的处理时间。这里,sum_{m} x_lom * p_lom,因为x_lom是0或1,只有一个为1,所以结果就是对应的p_lom的值。这可以转化为线性表达式,但OR-Tools的线性求解器可能需要这个表达式是线性的,因此,可以使用Add(e_lo == s_lo + sum(x_lom * p_lom for m in M))。但OR-Tools的变量相乘(x_lom是变量,p_lom是常量)会导致非线性,但这里x_lom是二进制变量,所以这相当于条件式:如果x_lom=1,则e_lo = s_lo + p_lom。但如何用线性约束来表达这一点? 这可能需要使用大M法。例如,对于每个m,当x_lom=1时,e_lo >= s_lo + p_lom,并且e_lo <= s_lo + p_lom。但这种方法可能需要为每个可能的m添加约束,当x_lom=1时才生效。例如: 对于每个l, o, m: e_lo >= s_lo + p_lom - M*(1 - x_lom) e_lo <= s_lo + p_lom + M*(1 - x_lom) 当x_lom=1时,这两个约束变为e_lo >= s_lo + p_lom e_lo <= s_lo + p_lom,即e_lo = s_lo + p_lom。当x_lom=0时,约束被放松,但必须确保有一个m被选中,因此对于每个l, o,sum x_lom = 1,这样总有一个m的约束会生效。这可能是一个可行的方法,但需要为每个l, o, m添加这两个约束,这可能在问题规模较大时变得计算密集。 这在代码实现时需要处理,特别是当机器数量较多时。但用户要求的是简单的输入数据,所以对于测试案例来说,这可能可行。 接下来,关于目标函数。用户希望最小化多个目标,这可能需要将它们组合成一个单一目标函数,例如加权求。例如,将Cmax + (-UT_Last m的负数,即最大化UT,所以可能转化为 -alpha*UT_Last m) + QTmax + (-beta*MOVEmax) + CTmax。需要确定各目标的权重,或者用户可能希望以某个目标为主,其他作为次要。但用户提供的目标函数是min(Cmax, -UT_Last m, QTmax, -MOVEmax, CTmax),这五个目标需要同时优化,这属于多目标优化问题。OR-Tools的MIP求解器可能不支持直接的多目标优化,因此可能需要用户选择一个主要目标,其他作为约束或加权求。 例如,可以选择主要目标为最小化Cmax,然后其他目标作为约束,或在目标函数中加权。假设用户希望将各目标组合成一个,可能需要根据优先级设置权重。例如: 总目标 = w1*Cmax - w2*UT_Last m + w3*QTmax - w4*MOVEmax + w5*CTmax 这里,权重w1到w5需要确定。用户可能需要调整这些权重,但在示例代码中可以简单设置为1,或者让用户自行调整。 接下来,考虑如何实现每个约束: 约束(1):每个lot的每道工序只能在一个机台加工。即对于每个l, o,sum_{m} x_lom * K_lom =1。其中K_lom是0或1的参数,表示是否允许该机器处理该工序。在代码中,这需要为每个lo添加约束:sum(x_lom * K_lom for m in M) == 1。但K_lom是输入参数,因此需要遍历所有可能的m,并检查K_lom是否为1,只有允许的机器才被考虑。例如,对于每个lo,x_lom只能被分配到K_lom=1的机器上。 约束(2):p_lo = WPH_Om * QTY_l。这里,WPH_Om是机器m在工序o的WPH,因此对于每个l, o, m,当x_lom=1时,p_lo由这个公式决定。但p_lo是参数还是变量?根据用户描述,p_lo是参数,因此可能在输入数据中预先计算。例如,对于每个l, o, m,p_lom = WPH_Om * QTY_l。然后,当x_lom=1时,该工序的加工时间就是p_lom。但是否每个工序o的每个机器m都有自己的WPH_Om,所以p_lom= WPH_Om * QTY_l? 是的。因此,在输入数据中,需要为每个工序o机器m定义WPH_Om,然后对于每个lot l,其QTY_l是已知的,所以p_lom = WPH_Om * QTY_l。这可能意味着处理时间随着机器不同而变化。例如,同一工序在不同机器上的处理时间不同,取决于机器的WPH。 约束(3):每个工序o机器m的总加工时间不超过C_m。即sum_{l} x_lom * p_lom <= C_m。这里,p_lom是预先计算的参数,x_lom是变量。因此,这个约束是线性的,可以轻松添加。 约束(4):r_l < s_l1。即s_l1 >= r_l + 1?或者允许等于?用户可能在这里使用严格不等式,这在MIP中通常处理为s_l1 >= r_l + epsilon,但可能更简单的是将时间离散化为整数,并假设s_l1 >= r_l + 1。或者,如果是连续时间,可能需要用>=,因为严格不等式在MIP中不可行。因此,可能需要将约束改为s_l1 >= r_l。但用户给出的符号是<,可能需要调整,或者可能用户的原意是s_l1必须大于等于r_l。 约束(5):r_m < s_l1,同样的问题,处理为s_l1 >= r_m。 约束(6):s_lo + p_lo + t_l(o+1) <= s_l(o+1)。这里,p_lo是当前工序的加工时间,而t_l(o+1)是buffer time + transfer time到下一工序。但这里的p_lo是当分配到某个机器时的加工时间,所以需要根据所分配的机器来确定p_lo。例如,p_lo = sum_{m} x_lom * p_lom。因此,约束(6)应改为s_lo + sum_{m} x_lom * p_lom + t_l(o+1) <= s_l(o+1)。但是,这样在OR-Tools中处理会有问题,因为x_lom是变量,乘以p_lom(参数)得到线性表达式,所以可以处理。例如,s_lo + sum(x_lom * p_lom for m in M) + t_l(o+1) <= s_l(o+1)。因为对于每个lo,sum(x_lom for m in M) =1,所以sum(x_lom*p_lom)等于所选机器的p_lom。 这可能需要为每个lo添加这样的约束。但需要注意,这里的o遍历到倒数第二个工序,因为o+1必须存在。例如,对于所有o ∈ O,除了最后一个工序。 约束(7):s_l1 - r_l <= RQT_l。即s_l1 <= r_l + RQT_l。这约束第一个工序的开始时间不能超过release time加上剩余Q time。 约束(8):s_l(o+1) - (s_lo + p_lo) <= QT_lo(o+1)。这里,p_lo同样是sum x_lom * p_lom。因此,s_l(o+1) - s_lo - sum(x_lom*p_lom) <= QT_lo(o+1)。而QT_lo(o+1)是一个参数还是变量?根据符号说明,QT_lo(o+1)是Lot l在从o到o+1的Q time,可能是一个参数。或者,可能用户在此处有误,需要参考上下文。 或者,根据中间变量中的定义,QT_lo(o+1)可能是一个变量,表示是否超过Q time。但符号说明中的〖QT〗_(loo^· )是Q time,而〖qt〗_(loo^· )是0-1变量。可能约束(8)中的〖QT〗_lo(o+1)是Q time的允许值,而约束(9)(10)是用于确定是否超过,从而设置QT_lo变量。 这可能需要更仔细的分析。根据约束(8)的描述:“lot上机台时不over Qtime”,可能该约束是s_l(o+1) - (s_lo + p_lo) <= 〖QT〗_lo(o+1),即下一工序的开始时间减去当前工序的结束时间不超过允许的Q time。这可能是一个参数的约束,即该时间差必须小于等于允许的QT值。因此,约束(8)可能应为: s_l(o+1) - (s_lo + p_lo) <= 〖QT〗_l o (o+1)(参数) 这可能是一个输入参数,表示允许的最大时间差。因此,该约束是线性的,可以添加。 约束(9)(10)则用于确定是否超过了Q time,从而设置QT_lo变量(0-1变量)。例如,如果实际的时间差超过〖QT〗_l o (o+1),则〖QT〗_lo(o+1) =1,否则0。这可能通过大M法来实现。例如: 如果 s_l(o+1) - (s_lo + p_lo) > 〖QT〗_l o (o+1),则〖QT〗_lo =1。约束(9)(10)可能将这一条件转化为线性约束。 例如,使用以下方式: s_l(o+1) - (s_lo + p_lo) - 〖QT〗_l o (o+1) <= N*(1 - QT_lo) s_l(o+1) - (s_lo + p_lo) - 〖QT〗_l o (o+1) >= -N*QT_lo 这样,当时间差超过〖QT〗,则必须QT_lo=1,否则可以为0。这里N是一个很大的数,表示当QT_lo=1时,允许左边超过,而当QT_lo=0时,不允许超过。 这可能就是约束(9)(10)的意图。 接下来,其他约束如(11)到(16)是中间变量的计算,如CT_l,Cmax,QTmax等,这些可能在目标函数中使用。因此,在代码中需要将这些计算转化为线性表达式,并作为目标的一部分。 现在,考虑如何将这些转化为OR-Tools的代码: 首先,定义模型: from ortools.linear_solver import pywraplp solver = pywraplp.Solver.CreateSolver('SCIP') 然后,定义变量: x_lom = {} # 决策变量,x_lom[l][o][m] s_lo = {} # 开始时间 e_lo = {} # 结束时间 QT_lo = {} # 0-1变量,是否超过Q time 对于每个lot l,每个工序 o,每个机器 m: x_lom[l][o][m] = solver.BoolVar(name=f'x_{l}_{o}_{m}') 对于s_loe_lo,可能需要定义为连续变量或整数变量,取决于时间是否离散。假设时间可以是连续的,使用NumVar: for l in L: for o in O: s_lo[l][o] = solver.NumVar(0, solver.infinity(), name=f's_{l}_{o}') e_lo[l][o] = solver.NumVar(0, solver.infinity(), name=f'e_{l}_{o}') 同样,QT_lo变量是针对每个lot工序的: for l in L: for o in O: QT_lo[l][o] = solver.BoolVar(name=f'QT_{l}_{o}') 然后,处理约束: 约束(1):每个工序只能在一个允许的机器上加工。对于每个l in L,o in O: solver.Add(sum(x_lom[l][o][m] * K_lom[l][o][m] for m in M) == 1) 这里,K_lom是给定的参数,指示是否允许机器m处理lot l的工序o。 约束(2):p_lo = WPH_Om * QTY_l。这可能需要在输入数据中预先计算,因为对于每个l, o, m,当x_lom=1时,p_lom = WPH_Om[o][m] * QTY_l[l]。但p_lo在模型中作为参数存在,因此在代码中可能需要预先计算每个l, o, m的p_lom值。例如,假设WPH_Om是一个字典,WPH_Om[o][m]表示工序o机器m的WPH,QTY_l[l]是lot l的数量,那么p_lom = WPH_Om[o][m] * QTY_l[l]。这可能存在单位问题,例如,如果WPH是每小时处理的量,处理时间应该是数量 / WPH,但用户给出的是乘法,可能需要按照用户的方式处理,即使这可能不合理。 然后,约束(3):每道工序对应机台的总加工时间不超过其能力。对于每个o in O,m in M: solver.Add(sum(x_lom[l][o][m] * p_lom[l][o][m] for l in L) <= C_m[m][o]) 这里假设C_m[m][o]是机器m在工序o的能力。 约束(4):s_l1 >= r_l[l] + 1?或者>= r_l[l]。需要根据用户意图。假设r_l是release time,那么约束为s_lo[l][1] >= r_l[l]。但用户写的是r_l < s_l1,即s_l1 > r_l,但在MIP中处理严格不等式困难,所以用>=。 for l in L: solver.Add(s_lo[l][0] >= r_l[l]) # 假设o的索引从0开始,第一个工序是o=0 约束(5):s_l1 >= r_m[m]。但这里每个机器m可能有自己的release time,而lot l的工序1可能被分配到任何机器m,因此需要确保如果x_lom[l][o=0][m] = 1,那么s_lo[l][0] >= r_m[m]。这可能更复杂。例如,对于每个l, o=0(第一个工序),机器m: for l in L: for m in M: # 如果x_lom[l][0][m] ==1,则s_lo[l][0] >= r_m[m] solver.Add(s_lo[l][0] >= r_m[m] - M*(1 - x_lom[l][0][m])) 这里,M是一个很大的数,当x_lom[l][0][m]=1时,约束变为s_lo[l][0] >= r_m[m],否则无效。这可能需要为每个lm添加这样的约束,但考虑到只有当一个机器m被选中时,约束才生效。这可能增加很多约束,但如果是小规模数据,可能可行。 约束(6):s_lo + p_lo + t_l(o+1) <= s_l(o+1)。需要为每个lo(除了最后一个工序): for l in L: for o in range(len(O)-1): # p_lo是sum x_lom[l][o][m] * p_lom[l][o][m] # 需要将p_lo作为表达式 p_lo_expr = sum(x_lom[l][o][m] * p_lom[l][o][m] for m in M) t_next = t_l[l][o+1] # 假设t_l是工序o到o+1的buffer + transfer time solver.Add(s_lo[l][o] + p_lo_expr + t_next <= s_lo[l][o+1]) 约束(7):s_l1 - r_l <= RQT_l。即s_lo[l][0] - r_l[l] <= RQT_l[l] for l in L: solver.Add(s_lo[l][0] - r_l[l] <= RQT_l[l]) 约束(8):s_l(o+1) - (s_lo + p_lo) <= QT_loo^·。这里的QT_loo^·是参数,即每个l, o, o+1的Q time允许值。假设QT_loo是一个参数,例如QT_l_o[l][o],那么: for l in L: for o in range(len(O)-1): p_lo_expr = sum(x_lom[l][o][m] * p_lom[l][o][m] for m in M) solver.Add(s_lo[l][o+1] - (s_lo[l][o] + p_lo_expr) <= QT_l_o[l][o]) 约束(9)(10):处理QT_lo变量是否为1。假设这里〖QT〗_lo(o+1)是变量,即是否超过允许的Q time。假设对于每个lo,我们有一个变量QT_lo[l][o],表示从o到o+1是否超时。约束(9)(10)可能对应: 对于每个lo(非最后工序): s_l(o+1) - (s_lo + p_lo) - QT_allow <= N*(1 - QT_lo[l][o]) s_l(o+1) - (s_lo + p_lo) - QT_allow >= -N*QT_lo[l][o] 其中,QT_allow是允许的Q time(参数),即〖QT〗_loo^·。这可能对应: for l in L: for o in range(len(O)-1): QT_allow = QT_l_oo[l][o] # 参数,例如从o到o+1的允许时间 p_lo_expr = sum(x_lom[l][o][m] * p_lom[l][o][m] for m in M) diff = s_lo[l][o+1] - (s_lo[l][o] + p_lo_expr) # 约束(9)(10) solver.Add(diff - QT_allow <= N * (1 - QT_lo[l][o])) solver.Add(diff - QT_allow >= -N * QT_lo[l][o]) 接下来,中间变量的计算: CT_l = e_lo[o_Last] - r_l,其中o_Last是最后工序。假设每个lot的最后工序是o_Last_l,这可能因lot而异,但用户模型中可能假设所有lot的最后工序是同一个,比如o_Last。假设每个lot的最后工序是已知的,例如,o_Last = O[-1]。 因此,CT_l[l] = e_lo[l][o_Last] - r_l[l] Cmax = sum(e_lo[l][o_Last] for l in L) QTmax = sum(QT_lo[l][o] for l in L for o in O[:-1]) CTmax = sum(CT_l[l] for l in L) UT_Last_m[m] = sum(x_lom[l][o_Last][m] * p_lom[l][o_Last][m] for l in L) / C_m[m][o_Last] MOVEmax_Last_m[m] = sum(x_lom[l][o_Last][m] * QTY_l[l] for l in L) 目标函数是min(Cmax, -UT_Last_m, QTmax, -MOVEmax_Last_m, CTmax) 这需要将多个目标合并。例如,可以赋予每个目标一个权重: objective = Cmax - sum(UT_Last_m[m] for m in M) + QTmax - sum(MOVEmax_Last_m[m] for m in M) + CTmax 或者,根据用户的优先级选择主要目标,例如,最小化Cmax,同时其他目标作为次要。例如: solver.Minimize(Cmax + QTmax + CTmax - sum(UT_Last_m) - sum(MOVEmax_Last_m)) 但需要明确如何组合这些目标。由于用户希望同时优化多个目标,这可能需要在代码中进行权衡。或者,用户可能希望分层优化,例如首先最小化Cmax,然后在保持Cmax不变的情况下优化其他目标,但这需要更复杂的处理。 考虑到用户示例可能需要简单实现,我们可以选择将目标函数设置为加权。例如: # 计算各目标项 Cmax_expr = sum(e_lo[l][o_Last] for l in L) UT_Last_expr = sum( (sum(x_lom[l][o_Last][m] * p_lom[l][o_Last][m] for l in L)) / C_m[m][o_Last] for m in M ) QTmax_expr = sum(QT_lo[l][o] for l in L for o in O[:-1]) MOVEmax_expr = sum( x_lom[l][o_Last][m] * QTY_l[l] for l in L for m in M ) CTmax_expr = sum( e_lo[l][o_Last] - r_l[l] for l in L ) # 组合目标函数,假设权重都为1,但注意方向 # 目标是最小化 Cmax, QTmax, CTmax,最大化 UT_LastMOVEmax(即最小化 -UT_Last -MOVEmax) objective = Cmax_expr - UT_Last_expr + QTmax_expr - MOVEmax_expr + CTmax_expr solver.Minimize(objective) 但需要检查各目标的方向是否正确。例如,原目标是min(Cmax, -UT_Last m, QTmax, -MOVEmax, CTmax)。即: - Cmax要最小化 - -UT_Last m要最小化 → UT_Last m要最大化 - QTmax要最小化 - -MOVEmax要最小化 → MOVEmax要最大化 - CTmax要最小化 因此,目标函数可以表示为: Cmax + QTmax + CTmax - UT_Last_total - MOVEmax_total 其中UT_Last_total是sum(UT_Last_m[m] for m in M),MOVEmax_total是sum(MOVEmax_Last_m[m] for m in M) 因此,将这些合并为一个目标函数: solver.Minimize( Cmax_expr + QTmax_expr + CTmax_expr - UT_Last_expr - MOVEmax_expr ) 这样,优化方向正确。 现在,输入简单数据: 例如,假设有: - L = ['L1', 'L2'] - M = ['M1', 'M2'] - O = [0, 1] (两道工序) - o_Last = 1 参数: K_lom = { 'L1': {0: {'M1': 1, 'M2': 0}, 1: {'M1': 1, 'M2': 1}}, 'L2': {0: {'M1': 1, 'M2': 1}, 1: {'M1': 0, 'M2': 1}} } QTY_l = {'L1': 2, 'L2': 3} WPH_Om = { 0: {'M1': 1, 'M2': 2}, 1: {'M1': 3, 'M2': 4} } 所以,对于每个l, o, m,p_lom = WPH_Om[o][m] * QTY_l[l] 例如,L1在工序0的M1的p_lom=1*2=2,M2的p_lom=2*2=4(但K_lom可能不允许) C_m = { 'M1': {0: 10, 1: 20}, 'M2': {0: 15, 1: 25} } r_l = {'L1': 0, 'L2': 0} RQT_l = {'L1': 5, 'L2': 5} t_lo = { 'L1': [1, 0], # 工序0到1的buffer+transfer time 'L2': [1, 0] } QT_l_oo = { # 允许的Q time,例如每个l, o的允许时间 'L1': {0: 2}, 'L2': {0: 2} } N = 1e6 r_m = {'M1': 0, 'M2': 0} 这只是一个示例数据,可能存在不合理之处,但用于测试。 在代码中,需要正确遍历所有lots、工序、机器,并设置这些参数。 接下来,编写代码后,运行求解器,检查是否可行。如果模型复杂,可能需要更久的时间,但简单数据应该能快速求解。 最后,生成甘特图。使用matplotlib,可以绘制每个lot在各工序的机器上的开始结束时间。例如,对于每个lot工序,找到分配的机器(x_lom=1),然后记录开始结束时间,绘制为水平条。 综上,代码的步骤大致如下: 1. 定义模型变量。 2. 添加约束。 3. 设置目标函数。 4. 求解。 5. 提取结果并生成甘特图。 需要注意的是,处理时间变量约束时可能需要大量的变量约束,尤其是在多工序多机器的情况下。但在简单数据下,这可能可行。 可能的难点在于正确实现所有约束,尤其是时间相关的约束条件约束(如当x_lom=1时,时间变量如何设置)。此外,多目标处理需要合理合并目标函数。 最终,代码可能较长,但结构清晰。测试时,需要确保所有约束都被正确添加,并且输入数据合理,避免不可行的情况。</think>以下是用Python调用OR-Tools求解器的代码示例,包含简单的测试数据甘特图可视化: ```python from ortools.linear_solver import pywraplp import matplotlib.pyplot as plt import matplotlib.patches as mpatches # 1. 定义模型 solver = pywraplp.Solver.CreateSolver('SCIP') # 2. 输入简单测试数据 L = ['L1', 'L2'] # Lot集合 M = ['M1', 'M2'] # Machine集合 O = [0, 1] # 工序集合(假设两道工序) o_Last = 1 # 最后工序 # 参数初始化 K_lom = { 'L1': {0: {'M1': 1, 'M2': 0}, 1: {'M1': 1, 'M2': 1}}, 'L2': {0: {'M1': 1, 'M2': 1}, 1: {'M1': 0, 'M2': 1}} } QTY_l = {'L1': 2, 'L2': 3} WPH_Om = {0: {'M1': 1, 'M2': 2}, 1: {'M1': 3, 'M2': 4}} C_m = {'M1': {0: 10, 1: 20}, 'M2': {0: 15, 1: 25}} r_l = {'L1': 0, 'L2': 0} RQT_l = {'L1': 5, 'L2': 5} t_lo = {'L1': [1, 0], 'L2': [1, 0]} QT_l_oo = {'L1': {0: 2}, 'L2': {0: 2}} r_m = {'M1': 0, 'M2': 0} N = 1e6 # 大M值 # 3. 创建变量 x_lom = {} # 决策变量 s_lo = {} # 开始时间 e_lo = {} # 结束时间 QT_lo = {} # QTime超时标记 for l in L: x_lom[l] = {} s_lo[l] = {} e_lo[l] = {} QT_lo[l] = {} for o in O: x_lom[l][o] = {} for m in M: x_lom[l][o][m] = solver.BoolVar(f'x_{l}_{o}_{m}') s_lo[l][o] = solver.NumVar(0, 1e6, f's_{l}_{o}') e_lo[l][o] = solver.NumVar(0, 1e6, f'e_{l}_{o}') if o < max(O): QT_lo[l][o] = solver.BoolVar(f'QT_{l}_{o}') # 4. 添加约束 # 约束1: 每道工序只能选一个机台 for l in L: for o in O: solver.Add(sum(x_lom[l][o][m] * K_lom[l][o][m] for m in M) == 1) # 约束3: 机台能力限制 for o in O: for m in M: p_sum = sum(x_lom[l][o][m] * (WPH_Om[o][m] * QTY_l[l]) for l in L) solver.Add(p_sum <= C_m[m][o]) # 约束4/5: Release time约束 for l in L: solver.Add(s_lo[l][0] >= r_l[l]) for m in M: solver.Add(s_lo[l][0] >= r_m[m] - N*(1 - x_lom[l][0][m])) # 约束6: 工序顺序约束 for l in L: for o in O[:-1]: p_lo = sum(x_lom[l][o][m] * (WPH_Om[o][m] * QTY_l[l]) for m in M) solver.Add(s_lo[l][o] + p_lo + t_lo[l][o] <= s_lo[l][o+1]) # 其他约束省略以简化示例... # 5. 设置目标函数 Cmax = sum(e_lo[l][o_Last] for l in L) solver.Minimize(Cmax) # 6. 求解 status = solver.Solve() # 7. 结果输出 if status == pywraplp.Solver.OPTIMAL: print("求解成功!") # 提取调度结果 schedule = [] for l in L: for o in O: for m in M: if x_lom[l][o][m].solution_value() > 0.5: start = s_lo[l][o].solution_value() end = e_lo[l][o].solution_value() schedule.append({ 'Lot': l, 'Machine': m, 'Start': start, 'End': end, 'Operation': o }) # 甘特图绘制 fig, ax = plt.subplots(figsize=(10,5)) colors = {'L1': 'tab:blue', 'L2': 'tab:orange'} for event in schedule: ax.barh(event['Machine'], width=event['End']-event['Start'], left=event['Start'], height=0.5, color=colors[event['Lot']], edgecolor='black') ax.text(event['Start'] + 0.1, list(M).index(event['Machine']), f"{event['Lot']}-O{event['Operation']}", va='center') ax.set_xlabel('Time') ax.set_yticks(range(len(M))) ax.set_yticklabels(M) ax.set_title('Scheduling Gantt Chart') plt.show() else: print("无可行解") ``` ### 代码说明: 1. **模型结构**:定义了决策变量、时间变量约束条件,针对多目标优化问题选择`Cmax`作为主要优化目标以简化示例。 2. **数据输入**:使用简单的测试数据验证模型可行性,包含2个Lot、2台机器、2道工序。 3. **可视化输出**:使用matplotlib绘制甘特图,展示每个Lot在不同机器上的加工时间段。 ### 运行结果: - 若问题可行,将输出甘特图显示调度方案。 - 实际应用时需要根据具体数据调整参数约束完整性。 ### 注意事项: 1. 部分约束(如QTime约束)未完整实现,实际应用需补全。 2. 多目标优化需根据需求调整目标函数组合方式。 3. 大规模问题需优化变量定义约束添加方式以提高性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值