' g1 g% Z" t* U两道工序与一道工序最大的区别在于三点: , v6 y$ T+ v0 j+ ~9 L * S8 c$ @# \2 X( ?1、开始要处理CNC任务分配:分配给第一道工序几台CNC,分配给第二道工序几台CNC?具体怎么布局? ) K% r; ?% I- Z# D* d. K* i ; x y+ w$ }3 q5 h M) n* X7 m2、加工过程可能仍然是一个循环,但是这个循环将可能会非常的庞大以至于不可能直观的看出来。3 n. E [) m4 s' Y
$ ^' A5 ~$ ?7 r8 v! ^, J! K3、两道工序的分配已经是一个严格的NP难问题了(即理论上无法在多项式时间内求得最优解)。 : i# A+ G+ ?% w9 B0 _; ^2 K1 t! \0 ?$ e
第一点我的想法很单纯——穷举,没错,就是穷举,除了显然不合适的分配方案外,其他方案都试一遍(虽然真的很蠢,但是我真的想不出到底能怎么办了) * b# u" U* m& T% o# e ' |9 t" j, I# Y( F第二点因为不存在循环则使用遗传算法需要设定一个相当长的染色体长度(我们设定的染色体是RGV为各台CNC上下料的次序,如果要考虑全过程的模拟退火遗传算法,则染色体长度大约在300~400左右)。事实上我也尝试了这个方法,结果从我写完这个算法我开始跑,一直跑到比赛结束算法依旧没有收敛[捂脸]。这里给出代码仅供参考(各位朋友要是有好意见也可以提出) ↓↓↓ " U4 \) d p B. R & X3 V; U1 A r/ v( t: q3 x- @+ D5 I( n# -*- coding:UTF-8 -*-8 @; j4 b, Z; u) n; L. Q# u
"""% E5 Z, ~0 `2 ]. ]1 p: [% q
作者:囚生CY V; D" H, z- C1 Q- V 平台:CSDN: t* K6 _9 f5 A
时间:2018/10/09 ; S! X8 b3 }+ e8 I4 I 转载请注明原作者 6 {. n) w5 S4 Z N, f. D" u4 _. n: y 创作不易,仅供分享7 ?# b3 |& p. ^5 P2 o/ G0 f# a; Z
"""& s, N! Q) j4 m, p4 L" a% C
import random; O- D2 o A ]5 l3 L( q5 i9 I6 T
. j7 g2 `3 A6 t9 Z7 \4 _# 第1组 8 N; a h. y$ T4 S# W' w5 m i( T7 r"""6 S# F; K+ F0 N0 u! `
d1 = 20 ) e8 @* Z1 z% h% gd2 = 33 7 H- C2 q" ?) S2 c$ Bd3 = 46 ; a; O( z8 n( K' r* e( yT1 = 400, u( g8 S* o" e" e# z& ~; f1 R
T2 = 3785 x; ?- c, H* v4 f' q+ k. I3 i0 o1 q
To = 282 H* A2 r* n7 l- Y5 n' P
Te = 31 9 k: t1 R: Q! w" g( |' pTc = 25 5 P) x- d9 T. z( k/ y- o: I"""3 f- z D# u" p6 h8 G7 |
: v) O% X ^5 N2 n
# 第2组 0 Q; e5 ~. r% E7 S$ L""" " E7 F) O3 I, [% P8 ?. Vd1 = 23 . b4 b) ?8 @4 T/ s" D' z+ k: qd2 = 41# ?8 s/ H& x, P
d3 = 595 t9 ?2 A( N6 U" ^0 M* P$ a/ t- B
T1 = 280 , a* g2 W8 l4 t5 \T2 = 500 # }3 E( p7 ~" U# KTo = 30 . H4 E' \ Q" r# B0 QTe = 35 2 r& `6 G6 q) @$ O, Y- L( gTc = 30 V$ m8 P) X. o1 Y1 k T: U, e"""% [! ~, W% Q1 `
P3 O( ~7 o7 u' S# o' B5 s" N9 d# 第3组. M+ S) ~; g9 A7 h+ k8 h
d1 = 18+ r3 \8 u3 F, z4 i: Z; w: y
d2 = 32( g. ?' l! e, p; Q- L6 X
d3 = 46# W+ r1 J- T- N9 W' T7 M1 V$ u
T1 = 455+ a0 m4 B0 j8 S O+ C8 r
T2 = 182 ! F) _+ S6 f- h* G: q2 x7 i: ATo = 27, _5 S8 \$ B$ p9 F& Y# d) n p
Te = 326 J O) J" u& f; p8 O* t
Tc = 25. N; g2 }) W5 H/ _& @7 ]
# z/ i0 v& m/ w% |' _cncT = [To,Te,To,Te,To,Te,To,Te]5 u; j7 }/ N; A9 @
tm = [2 J% U4 O$ ~2 `7 ~3 b' T1 C
[0,0,d1,d1,d2,d2,d3,d3],# B" W' c |6 |% e6 D& A" f
[0,0,d1,d1,d2,d2,d3,d3], ) J6 A( F& B: k [d1,d1,0,0,d1,d1,d2,d2],$ i) x+ d1 H0 f! R
[d1,d1,0,0,d1,d1,d2,d2], W* k) |; N. U$ o- V: h Z4 T$ v
[d2,d2,d1,d1,0,0,d1,d1], 8 ^/ q, Z6 G+ r5 F [d2,d2,d1,d1,0,0,d1,d1], 8 C6 l! e1 @/ e [d3,d3,d2,d2,d1,d1,0,0], B5 w0 a& o. D0 ?& E% O
[d3,d3,d2,d2,d1,d1,0,0], 3 { N: u+ v6 ]2 i, k]& l2 t$ S+ c5 o3 F7 S
Type = [1,0,1,0,1,0,0,0] # CNC刀具分类 # W# c+ Z- g+ {& f 7 K! P; c9 E5 ^! v. QN = 64. p' U' y' O: A. G7 h" T
L = 100 % r5 V( ?6 O& avarP = 0.1* M) B3 B% K6 z. K; V2 j9 `
croP = 0.6 % x! a( Z9 z PcroL = 2 , C! k' q0 J9 d$ O4 l6 r, Le = 0.994 Y% b4 `, ]% m1 k% w% C; f: R
: c k* b+ s% ^1 M' m. Xdef init_first_round(): # 第一圈初始化(默认把所有第一道CNC按顺序加满再回到当前位置全部加满)8 _% y3 ?1 l( d$ Y8 o5 W5 b7 g
state = [0 for i in range(8)] # 记录CNC状态(还剩多少秒结束,0表示空闲) ; \4 G- l9 P" e5 ?! x! v isEmpty = [1 for i in range(8)] # CNC是否为空+ Z, h0 I. [! v; B% ?+ r
rgv = 0 # rgv状态(0表示空车,1表示载着半成品) % `9 u9 o8 Q) g! x# y8 L currP = 00 g5 w! z3 k0 \
total = 0 $ y# m; `( v* s+ | seq = []9 Q6 o* |4 I6 }; z- l* C+ w
flag = False' t: f( X O6 [! \9 n+ |. X
for i in range(len(Type)): , ^! {3 t- C _/ b if Type==0: ( j4 t* k v/ y0 u7 h seq.append(i), Y5 \: W& ]) D; G% k0 [
flag = True 7 k! g% D, F$ R, o0 M/ G1 T3 L currP = seq[0] + z: }; ~- ~2 ~ seq.append(currP) $ J2 P1 P9 ^& Q U6 ~ rgv,currP,total = time_calc(seq,state,isEmpty,rgv,currP,total)( o1 J5 _3 @# E: J7 m" D$ M
return state,isEmpty,rgv,currP,total,seq : X# g! J+ t5 [2 }4 [' A& |4 F8 J9 M8 z( l1 D4 V, b/ a0 K& w3 L
def update(state,t):$ z ^. @& R, \9 m8 x! J
for i in range(len(state)): + x6 [% S1 m" } if state < t: * Z0 `1 R: \+ ]% m state = 0 3 P2 [2 x' _0 x else:+ H1 L. w. w2 u; L( ?# u" A1 V3 T+ }/ s
state -= t % Y2 q) [( @3 O+ b( _: ^) I% ]' N* N5 }: o
def time_calc(seq,state,isEmpty,rgv,currP,total): # 事实上sequence可能是无效的,所以可能需要 " N: ]$ N5 J: W. Z) D index = 05 H: y( z3 t7 G" ?/ X
temp = 01 {1 Y. M. J( q: X- {; q, R J
while index<len(seq):1 ^$ u! L/ P, j4 C4 v# E$ m+ W
""" 先移动到下一个位置 """ ) u8 W; }6 G6 X3 E. i nextP = seq[index] $ {2 r3 |1 t0 Y+ I t = tm[currP][nextP] 9 }: E6 ~, r# l total += t) C( j" b' Z% V1 e1 O1 b( D% w( ~
update(state,t) ; Z9 r4 w/ V' m- S5 v# h% q5 P if Type[nextP]==0: # 如果下一个位置是第一道工作点( B. h. \5 S( M) ~
if rgv==1: # 然而载着半成品! L, S0 K9 F0 P; }( l
seq.pop(index) # 去掉这个元素并中止当次循环进入下一个循环' V5 \& d X( w8 `) r
continue # d) }5 @3 d; r/ R( q if isEmpty[nextP]: # 如果下一个位置是空的 / z9 u" \2 e; Y' k' Q t = cncT[nextP]8 W6 w2 @$ g. O/ o9 l$ \9 y
total += t3 A: U) e0 D& X# R e
update(state,t) - X) i* o3 {0 `3 y state[nextP] = T1 # 更新当前的CNC状态5 P' ~' E( {0 R- o; ~! e. e" u& X) z
isEmpty[nextP] = 0 # 就不空闲了 . ~4 o% [) E3 U; R$ X else: # 如果没有空闲; w2 c$ ]) z( B: b
if state[nextP] > 0: # 如果还在工作就等待结束 + w2 P+ G. V, Y t = state[nextP]0 J( g3 x3 ~$ f: l% ^. r7 f
total += t, o. r& u/ R5 ^. G& m
update(state,t)2 R4 Z/ h2 U( S4 t
t = cncT[nextP] # 完成一次上下料3 O9 v" `2 X- _4 }3 ?
total += t + y4 ~' N+ w" ~5 q9 ]. X5 i0 ~ update(state,t) 7 u8 G3 C* p- Q state[nextP] = T1- V0 A2 ?& O r0 P
rgv = 1 ; a% N3 P5 l2 Y+ m1 q else: # 如果下一个位置是第二道工作点 " F$ C5 A' H2 P0 Q) u% ~2 x% v if rgv==0: # 如果是个空车) ^$ c" M" Q3 Z$ B
seq.pop(index) # 删除当前节点, P8 ~4 v+ f( P
continue ) {+ j' j7 F6 [: i( X if isEmpty[nextP]: # 如果下一个位置是空的7 b$ [& W2 m4 G% b/ I) ~
t = cncT[nextP], W4 N0 y7 T- w, B; i5 E4 o
total += t$ q4 A K- t' l7 j# K
update(state,t) _9 g( ~5 [2 C/ T5 A% ]
state[nextP] = T20 F! _0 s( M$ k: N! Y' X' D7 i
isEmpty[nextP] = 0 # k; [$ @) l5 u& d. Y1 K" k else: # 如果没有空闲 0 N8 K$ b( c: x7 K' F$ R ^! t- W if state[nextP] > 0: # 如果还在工作就等待结束# g: \3 \6 K' G/ P/ C4 P
t = state[nextP] " \) x+ N1 }4 @3 U total += t 1 [5 a; Y* O( p2 x$ L2 ]' l update(state,t)3 A/ M# g. r" w
t = cncT[nextP]+Tc/ B0 ?6 C8 I |7 V( |, |# s
total += t 5 h9 i2 B( u1 T" g- r* q update(state,t); s: }( [% a5 O% J) E; I7 Q
state[nextP] = T2# l( ]" x. Y# |% N t. [; K. j
rgv = 0. t+ g$ c3 D) `* H0 r) ]
currP = nextP4 y2 N5 V$ _. o* Q; A3 Y
temp = total 9 s- ~! E2 ]. `- O* Z! Y( |0 }! H2 z
index += 1 2 A6 D: C9 v+ e! P& K total += tm[currP][Type.index(0)] # 最后归零 1 x; [; e9 N2 y/ y$ z0 k* D return rgv,currP,total A. I& _$ o K/ [
8 @. J/ f9 i* ]1 d" Y5 d2 z9 sdef init_prob(sample,state,isEmpty,rgv,currP,total): # 计算所有sample的9 y: Z O- M4 e: g9 I7 J
prob = [] / Y3 @* Q. _; c( R3 a' K, V for seq in sample:4 U; T) _: h; j: s% ?4 B
t = time_calc(seq,state[:],isEmpty[:],rgv,currP,total)[-1] & B8 J8 C1 {5 C4 s+ I0 l prob.append(t)- v, O. z7 W/ F; m' M& Q4 B' u* Q! ?
maxi = max(prob); K0 U/ h2 d4 r
prob = [maxi-prob+1 for i in range(N)] 2 b. I h2 z4 }' w0 y temp = 0 ) C/ q8 L+ `; ~5 M6 _5 x for p in prob:- F1 f, P" _8 X- x) J
temp += p & q5 I$ Z" r# [* W j) x& u prob = [prob/temp for i in range(N)]* z* g8 {0 c8 r' i" W
for i in range(1,len(prob)):$ ^0 z, u, c f( j3 o1 d1 j3 s/ n
prob += prob[i-1] r" W! S3 B+ L0 ^. H prob[-1] = 1 # 精度有时候很出问题; F/ E0 N4 Y' K; x
return prob ]! q |+ O) S- J0 L3 U9 ] 9 F+ M# `: Y! |1 B" j: q$ rdef minT_calc(sample,state,isEmpty,rgv,currP,total): ' l1 v. b, m: o" }2 D minT = time_calc(sample[0],state[:],isEmpty[:],rgv,currP,total)[-1] 5 h# `: M: M& w+ R) r* w; l4 R! Z _2 p index = 0! s1 G" ]0 T$ s
for i in range(1,len(sample)):; B% T& n% y9 G. w2 a8 I- e
t = time_calc(sample,state[:],isEmpty[:],rgv,currP,total)[-1]0 ~ c8 z6 A: v* [
if t < minT:* }4 L% d- h. |1 f
index = i $ F3 {+ \. Q' V minT = t& M/ m- g: l& R: F: p
return minT,index Y8 N, n& [ Q1 O+ n 3 R0 m# h5 _, `, e
def init(): # 初始化种群(按照第二道工序,第一道工序,第二道工序,第一道工序顺序排列即可)# O5 M$ p; J& }9 K0 N
sample = []6 U( L+ I" Z; V8 |" w+ D }' V
refer0 = [] j. t5 J- g" t, ~0 s refer1 = [] ( a% {3 u" M3 W4 f for i in range(8): 8 ?. g! v/ O- u( k1 k if Type==0: , j' A' s( q0 i refer0.append(i) * l! W1 p4 S# ^2 ^" W4 [! v% W else: , Q2 v* s2 b8 |2 g8 Q% K: J refer1.append(i) ) G e# T$ o/ n, N$ F" i for i in range(N): 5 I" p, n6 Y$ |0 [# M; m, b5 U5 [" P5 I p! M sample.append([])% B% E7 f; W% X5 ^
for j in range(L): - W5 d2 J' b3 x9 W if j%2==0: 5 e5 F. z% R; s' W; R$ N sample[-1].append(refer1[random.randint(0,len(refer1)-1)])* V* q6 I- v G/ ?, L
else:0 v% U* {, @# O: |
sample[-1].append(refer0[random.randint(0,len(refer0)-1)])5 [4 k% h& W; D
return sample6 C3 a% E3 D7 M, d- o
6 B! R( c. B& cdef select(sample,prob): # 选择算子 ( U& z- W7 H& h: N/ a+ ` sampleEX = []0 i7 u7 ^6 v+ U1 r- }9 _/ r
for i in range(N): # 取出N个样本 6 ?$ `: q6 t2 }. @ rand = random.random() 2 @) e; F8 S9 }/ v0 G0 N/ d6 E# f m4 l for j in range(len(prob)):4 V }! N6 `3 e) p+ [
if rand<=prob[j]:( I# {2 j1 C5 R0 b
sampleEX.append(sample[j]) . G$ j2 `; f1 l f, J* i break5 D9 h3 K9 ? M J# x5 k) w
return sampleEX: D" _0 k7 A7 n& \# U+ ~+ Z) E
! Y: m# S7 y3 Edef cross(sample,i): # 交叉算子0 b( [8 m6 O% k- X- v& H! K" O
for i in range(len(sample)-1): # q2 X0 h' L. j) ~& _/ l, N3 l for j in range(i,len(sample)):4 q: ]! e6 D3 W" f! H
rand = random.random() + ]: \6 w9 l& v& M" h/ o if rand<=croP*(e**i): # 执行交叉 , z9 e$ I. U7 M loc = random.randint(0,L-croL-1)- W$ j; c! n8 N. f2 `% d" U; X3 G
temp1 = sample[loc:loc+croL]$ n# r; a& N, a8 v5 E T {: t
temp2 = sample[j][loc:loc+croL] 0 ]: k& v- b; C3 g for k in range(loc,loc+croL):4 q- R8 U# k& o/ T2 W! y) N
sample[k] = temp2[k-loc]4 R: [ J$ |; Q. N0 G. N
sample[j][k] = temp1[k-loc]( P! x+ @2 v: ]7 y
return sample 6 Z! v% X/ |8 D7 v; x" H- [ + r" D0 Z, C0 X' z/ zdef variance(sample,i): # 变异算子 1 ?% p$ F( i o& a1 X6 u" U for i in range(len(sample)): : G% o2 S1 p3 J* G2 S rand = random.random() 0 ^7 q' h# w& z6 E- ~6 a if rand<varP*(e**i):" k* J0 E2 o4 I" @+ a
rand1 = random.randint(0,L-1) " _2 w `7 y1 V5 w; Y8 B6 Y* {$ a randTemp = random.randint(0,int(L/2)-1)* V4 `7 `* ]1 }4 }" S* F' l
rand2 = 2*randTemp if rand1%2==0 else 2*randTemp+1 , h" \) ?( X2 C- v; t- _ temp = sample[rand1] : g+ S- r4 |- c! N0 C9 I9 p+ ~ sample[rand1] = sample[rand2] 2 l1 ~0 {: j( Z2 S; y3 V sample[rand2] = temp % f$ }9 Q* a5 M+ g4 f return sample 5 [1 t3 O0 y2 k6 v& `, P5 k( t' p' z 2 |4 G# m5 L' u3 _7 _' aif __name__ == "__main__":/ V0 W& o7 ?+ g' n: A
state,isEmpty,rgv,currP,total,seq = init_first_round()+ J F& r9 J" o/ \- V8 F) q$ M1 s* C
print(state,isEmpty,rgv,currP,total) . e" k+ z2 N- i( A: A! Z3 h% @) [ sample = init() / K3 G1 g# ]( l! W mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 3 b0 ^$ |+ d$ W0 s+ \% h: L z best = sample[index][:]; M# A* Z) P9 |1 W
for i in range(100000): + O+ o1 J+ y0 o, ]" p# z; N% Y5 I7 j! [ f = open("GA.txt","a")) q( N) q6 e- e+ x
tmin = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)[0]4 m5 K4 @7 t" P, k, r8 [, q
f.write("{}\t{}\n".format(i,tmin)) / o' q3 p/ {* [' \: t print(i,"\t",tmin,end="\t") % F9 f$ h7 f& U- x% p! B2 | prob = init_prob(sample,state[:],isEmpty[:],rgv,currP,total) $ _4 x7 I0 j& m sample = select(sample,prob) ) W V2 X. ]8 o* A' j; a+ O) H2 D sample = cross(sample,i) - j$ B( R; |+ I sample = variance(sample,i) / T5 O* I& m! K& T mi,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total) 5 K% @# `/ o0 [/ Q% j# v, g if mi>mini and random.random()<e**i: # 精英保留策略0 c6 ] u! [7 W
rand = random.randint(0,N-1)1 z4 ]. w& ^4 Y7 ^: `, e: z
sample[rand] = best[:]9 T# D8 f' O1 h( b/ H6 o& o
mini,index = minT_calc(sample,state[:],isEmpty[:],rgv,currP,total)! I, ~1 k9 I8 f# L
best = sample[index][:] : E1 `) ?0 X+ g: C# G; n1 V1 x3 j print(best) 4 p* j' e2 B" }& Y1 h r/ S2 P( @ f.close() z' w0 Z- `- e: q' g }4 P4 P: J
print(sample)5 b6 ]( q7 M8 B, w+ [ e2 x. b
遗传算法这条路被堵死后我一度陷入俗套,用最直接的贪心搞了一阵子,觉得用贪心算法(即考虑下一步的最优策略)实在是对不起这种比赛。然后我就变得——更贪心一点了。* d$ j; ~1 Z9 I) O
" Z; H+ X0 Z) w. d$ mcncT = [To,Te,To,Te,To,Te,To,Te] ! @/ b2 f! r- i3 q2 Z- \tm = [( i. J, _( L3 k6 ?4 U# t
[0,0,d1,d1,d2,d2,d3,d3], 4 l8 ]" @- O) _) @8 h0 H G. k [0,0,d1,d1,d2,d2,d3,d3],) J& o4 P: l! X! ~/ A! ~: F
[d1,d1,0,0,d1,d1,d2,d2],4 [: b* B0 y9 @* f- w% x( W8 K
[d1,d1,0,0,d1,d1,d2,d2]," Q# n, N& n3 z2 B
[d2,d2,d1,d1,0,0,d1,d1]," O8 `3 t( x( g% b4 t* Y2 m
[d2,d2,d1,d1,0,0,d1,d1], 1 ~4 f; o# |; @8 ^8 V2 Z- B [d3,d3,d2,d2,d1,d1,0,0],: X! n9 g' d4 P7 X
[d3,d3,d2,d2,d1,d1,0,0], * U2 k/ B* o }1 i" e. u% }] 7 b& g8 N2 a; W5 }& `; m0 P( [8 c$ gType = [0,1,0,1,1,1,0,1] # CNC刀具分类 : V0 f* H7 Q' ^* W t3 C2 k z$ G' s# v9 b3 h
A = [] # 储存第一道工序的CNC编号 . h5 y. s& S0 r9 JB = [] # 储存第二道工序的CNC编号# q. u( o+ s, Q ]8 S
for i in range(len(Type)): : m2 O; q0 i3 i X! |) P% P" l" j if Type: 1 {6 s! p4 X+ [2 I1 k7 W B.append(i) 0 `: s3 [5 t$ Q3 o else: . A% ?7 {8 O0 r A.append(i)# M1 g* K% j5 [2 K8 z& f
4 X( v' W. S3 q2 _+ B9 t$ ^2 @: L! {8 D
def init_first_round(): # 第一圈初始化(默认把所有第一道CNC按顺序加满再回到当前位置全部加满) : ^0 P9 g/ A* W; E9 s state = [0 for i in range(8)] # 记录CNC状态(还剩多少秒结束,0表示空闲) & B* | |# a& O7 ]0 u+ b$ y isEmpty = [1 for i in range(8)] # CNC是否为空4 E4 a% T& q; ~/ H9 ]9 B/ i
log = [0 for i in range(8)] # 记录每台CNC正在加工第几件物料 " d) ^) w/ e7 d/ Z* a8 n9 l: T) j0 [ count1 = 0 ' n. i0 ~1 n1 W5 _ rgv = 0 # rgv状态(0表示空车,1表示载着半成品)% \' r+ ]2 L( v$ r* i ~8 [ g
currP = 0" g; F: n& \' f1 z. B$ x; Q8 e3 x
total = 0 ! D# y1 N6 G/ K$ k7 C8 B seq = [] 7 s" w, R1 Z& | flag = False3 Y E: a6 k, Z. g
for i in range(len(Type)):) b( e6 h& k+ g2 a+ a* \
if Type==0:1 A$ H! L( z8 A7 I
seq.append(i); c8 |! _0 L$ R1 E# p, P
flag = True7 V; J: q4 b( z0 h
currP = seq[0] + b. a. W3 I+ m: J seq.append(currP) 9 `2 T- |4 A# m# G! w5 S count1,rgv,currP,total = simulate(seq,state,isEmpty,log,count1,rgv,currP,total) 7 N( w' c- g; w/ A return state,isEmpty,log,count1,rgv,currP,total,seq6 u* x1 ^& U/ M, r6 X* o# j
: g6 ?( |. E0 o1 T9 S/ v6 s0 Mdef update(state,t): 6 T; B b/ [8 D) X8 Z for i in range(len(state)): 1 @$ t* \" [( o+ u0 a7 Z if state < t: * m$ w1 s; a$ `- ^5 I& s state = 0 * v" e W- B! x else: / o9 h3 o: A8 h1 ? state -= t 4 V" e' w3 ~; Y0 v 5 A! H$ h4 p. b1 }) T8 gdef simulate(seq,state,isEmpty,log,count1,rgv,currP,total,fpath="log.txt"): # 给定了一个序列模拟它的过程以及返回结果(主要用于模拟并记录)* a% u+ l9 u3 B5 X1 p0 k9 E: a
index = 0: G8 p4 F8 b/ {7 \( b: t
temp = 0$ g" {! s- k& X
pro1 = {} # 第一道工序的上下料开始时间( B% P' D# x! a' j+ Q( p
pro2 = {} # 第二道工序的上下料开始时间5 a% e/ |$ @# N2 E2 D: v3 g+ n) Z! {
f = open(fpath,"a") ' z7 N" f' Z8 L& J4 C( _1 e/ F while index<len(seq):- |+ g5 c1 K4 i O: k7 r
print(isEmpty)/ |9 m9 j, R! O L( q
nextP = seq[index] + c3 N. n: N' |* A3 K' n t = tm[currP][nextP]4 N' {; r$ J5 ?- O9 @' {5 P8 m
total += t 4 D& m ?: @% [* z update(state,t)7 k: Z0 F. |3 _
if Type[nextP]==0: # 如果下一个位置是第一道工作点8 ~8 X5 c2 j; P3 j
count1 += 1- x" _' S3 l( z% }, D( y+ F
if isEmpty[nextP]: # 如果下一个位置是空的5 L8 t r3 }5 H, ~
f.write("第{}个物料的工序一上料开始时间为{}\tCNC编号为{}号\n".format(count1,total,nextP+1)) ) |3 N- @9 |" \5 r3 Y( R t = cncT[nextP]0 u3 f/ T* @3 _
total += t4 s' w1 q' a9 q: w$ B/ j/ ^
update(state,t) + N6 Z2 ?8 r/ |& r5 y: I state[nextP] = T1 # 更新当前的CNC状态 * {7 r' z5 K4 h8 l: k2 n isEmpty[nextP] = 0 # 就不空闲了7 I9 H* G% A* ?$ O, I: n
else: # 如果没有空闲 8 F! [7 n% x. _) c* ~ if state[nextP] > 0: # 如果还在工作就等待结束 ! _8 p; o% v6 a, A" y% @+ W& K' X t = state[nextP]. ? H4 q/ B+ |+ b
total += t, u3 v% r3 d. o/ C' `4 s2 B
update(state,t) ! G+ e' E' d4 ~+ Z* X5 L6 V) X f.write("第{}个物料的工序一下料开始时间为{}\tCNC编号为{}号\n".format(log[nextP],total,nextP+1))% q/ |% B* w" ]
f.write("第{}个物料的工序一上料开始时间为{}\tCNC编号为{}号\n".format(count1,total,nextP+1)) 5 T' b$ k- j1 B# v, } t = cncT[nextP] # 完成一次上下料 3 G9 w: {8 O" t8 f9 g total += t c S- I& {# b7 w$ \6 A
update(state,t) 3 p6 U) O7 g8 Q' R8 C7 s( b5 m# t9 |' G state[nextP] = T1 % \& K0 Z( g( [ rgv = log[nextP] 8 ]3 R4 e1 ^0 O! y {+ T1 H7 h log[nextP] = count1$ h& c3 m% Q) _2 v9 ?
else: # 如果下一个位置是第二道工作点+ l9 c" f9 r# o5 Y- W& @; G
if isEmpty[nextP]: # 如果下一个位置是空的9 G+ v$ b. k5 u/ Y G5 v$ @
f.write("第{}个物料的工序二上料开始时间为{}\tCNC编号为{}号\n".format(rgv,total,nextP+1)) 0 @4 [( Z4 q9 ?$ n9 R( o' R5 `# p9 F t = cncT[nextP] , I' ]. d5 I9 [+ A0 ^5 ]4 M total += t " g' I2 I: ~- t2 y# { update(state,t) * h' }0 Z$ c- }; M6 \ state[nextP] = T2 ]% o% L5 e1 r$ |' ]) k
isEmpty[nextP] = 0 ( h5 m: ^& z3 _7 w- V: w: P% {
else: # 如果没有空闲 0 c" e+ A% f% ~2 L/ \1 f5 A f.write("第{}个物料的工序二下料开始时间为{}\tCNC编号为{}号\n".format(log[nextP],total,nextP+1)): O8 e0 y: q3 t$ ] ] U4 g @. ?
f.write("第{}个物料的工序二上料开始时间为{}\tCNC编号为{}号\n".format(rgv,total,nextP+1)). F: v9 B, R$ F$ T
if state[nextP] > 0: # 如果还在工作就等待结束, n1 h$ [5 r6 R0 H; H' ?
t = state[nextP]8 T. t R' Y. A3 N! j. l/ a
total += t ! z- q+ h. K& x4 B update(state,t) " N. a- z5 ?( Q- p1 H t = cncT[nextP]+Tc; ~- A! O% h h; n* F
total += t$ t) g% k r0 j! L8 K3 n) V2 J
update(state,t) 1 n3 A: K0 v- @3 `) j4 I- a state[nextP] = T2 * s4 Z* I# @& w log[nextP] = rgv 0 T( k$ E5 I+ a1 y4 Y, C rgv = 0 * j/ B% A/ S7 V# B( M% d currP = nextP8 B& F. y/ F9 {% s2 o8 u
temp = total ) g. H" @3 Q5 T2 i* H
index += 1 & A I3 _: y/ c+ h6 z5 m
f.close() * o1 {- F$ B7 p; n total += tm[currP][Type.index(0)] # 最后归到起始点 1 b7 |. a3 r' P+ g% ~& d; B return count1,rgv,currP,total / r& N" X! J! p& }" @( v7 H& T0 R$ H3 T3 Z( k5 P# H
def time_calc(seq,state,isEmpty,rgv,currP,total): # 主要用于记录时间8 [3 i) c2 Y7 f9 O
index = 0( ~; R' a' Z0 e3 B3 M2 u
temp = 0 o" n% `- n. p! E0 D- E; i& a
while index<len(seq): ' `1 o( b* R; ~$ X nextP = seq[index]3 D1 U ~/ P' ]7 I' g7 ?
t = tm[currP][nextP] 2 _9 z7 n" }( E: o. _5 ~+ C' N total += t' {* x, G! Q9 t
update(state,t)/ Z6 A3 c$ u! T i+ \
if Type[nextP]==0: # 如果下一个位置是第一道工作点 ! W" ~+ G& X8 ^1 o2 L9 M ? if rgv==1: # 然而载着半成品 C# p8 M. K' H) Q" t+ I7 H! B seq.pop(index) # 去掉这个元素并中止当次循环进入下一个循环. D$ {7 J' s2 m
continue 8 A# F4 ~6 b; U1 r2 ?9 v+ S
if isEmpty[nextP]: # 如果下一个位置是空的$ r' b; z- a8 [. {! }; X2 A9 H
t = cncT[nextP] 4 b# X+ O1 C- k total += t * n+ b# c+ A* @" J+ e update(state,t) 8 ]1 D- X3 S4 F2 G8 b9 j state[nextP] = T1 # 更新当前的CNC状态! x. w$ r- o& z0 L0 W1 h% u
isEmpty[nextP] = 0 # 就不空闲了( Z! b' F5 z! Y
else: # 如果没有空闲 0 |) w1 n F# h. l6 o; _9 \ if state[nextP] > 0: # 如果还在工作就等待结束! ^ ?1 w! _" V! g2 J, w, e
t = state[nextP] ) ~3 c3 e, q1 q/ p; X( q$ c total += t h7 V" B3 }% O
update(state,t)# s& f! R/ k; A, p/ g6 v
t = cncT[nextP] # 完成一次上下料 u; w; W8 t$ f% L8 {7 N; Z total += t % |" F G# Q# F/ W! O update(state,t) - D+ g1 Z+ t+ }. ]* L9 d; X; E state[nextP] = T1 9 v+ s3 i/ t$ z) Z9 l- W rgv = 1 8 [0 J: [" i) n/ X else: # 如果下一个位置是第二道工作点 ) K8 M6 x( u, Y2 \ if rgv==0: # 如果是个空车7 X$ f1 j7 l- C. A" f7 M
seq.pop(index) # 删除当前节点 2 D+ }- b: @/ ], u8 j- a continue , D9 B" K( |" D( b/ T% N if isEmpty[nextP]: # 如果下一个位置是空的 0 X( `3 T2 M3 } t = cncT[nextP] 8 S8 d+ T# H: x! e! U$ h total += t # C9 z7 J3 e- a$ M update(state,t) 7 o L" T% ] n state[nextP] = T2$ [# V8 I) W1 a% p
isEmpty[nextP] = 0 ( m3 b. Q) i- u5 S else: # 如果没有空闲. K$ r4 [- A, d6 O3 i4 ^
if state[nextP] > 0: # 如果还在工作就等待结束 ) \# I2 `) x6 y7 ]2 Z9 A& e t = state[nextP] 8 S* }1 K+ `1 I total += t 9 x/ I8 P9 o. t2 n) R6 x update(state,t) 1 l' A0 L- o+ E* t, y t = cncT[nextP]+Tc- Z, k3 j, y' G) b m, o) V
total += t+ B$ z; ~" W5 j2 L, g+ P( y
update(state,t) + i1 q7 x, b8 ]: v& G6 A+ f) ]* o state[nextP] = T2 + A# N6 X; n8 o, ^3 X: H- H rgv = 0% p/ x" s3 { S2 N5 x
currP = nextP 7 b; V2 i, W) Z3 u* K4 v% a temp = total 5 i. h% W/ d q" |6 N$ d$ z index += 1 & e1 U4 r5 m# y) A- y
return rgv,currP,total1 x6 Y0 M4 c$ n) s" K7 e+ z
/ u( l& J% C: l4 c
def forward1(state,isEmpty,currP): # 一步最优9 p- x s# ~! l
lists = []: A3 K5 M6 P$ z8 Z7 e' T
if currP in A: 9 C1 [& R# g P1 G: _# ^) @* ?7 D rgv = 1, B4 ]2 \0 y, r5 o
for e1 in B: . |/ C" K& z# D# x3 y, s lists.append([e1])6 v5 T: L- ?+ }# u; J/ W# x# C
- |' {. C8 H2 a7 \6 S else:6 c6 m; X% D3 C
rgv = 0: x" V6 K: I# L" K
for e1 in A:$ r# }8 y, T% h1 I, I! k6 |5 J
lists.append([e1]) ; {; U) C6 p* S9 W; C # M1 U" j/ a1 V9 j- l" U- w
minV = 28800 * H! w( E4 Q' \9 H* g" D for i in range(len(lists)):4 i& x% b; J9 o! j
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1]8 R. H# K* w5 `7 T: ?4 t* g; b
if t<minV: 1 R- ]; ]5 k* t1 v* K) @# r! Y1 ] minV = t) N t. p& V* L; D U- L
index = i & x4 B9 S B, ~ return lists[index][0] # \# X7 z5 |- d1 {* g4 g% Y4 Z. `
def forward4(state,isEmpty,currP): # 四步最优 0 @4 ~. b/ e$ L* {, x8 | lists = [] % m$ ^* ` U& J* H6 e) ] """ 遍历所有的可能性 """/ D; N# v2 ]' u$ t4 Y1 n' t1 t$ N
if currP in A: # 如果当前在第二道工序CNC的位置% [) b4 p- t5 p+ R! \
rgv = 1% X7 K" ?5 G# b4 M* ~6 N" o
for e1 in B: ) K- f; O: b$ ~7 W9 u for e2 in A:5 L- y/ C8 W3 n3 b4 X
for e3 in B:0 J8 I+ C( v8 e% P
for e4 in A:! X/ [$ u4 l L X" v3 t& J
lists.append([e1,e2,e3,e4])( G4 S; K' H' V! |% G
else: " q* G: E1 m) c; D& f rgv = 0 % b& y* e' u1 P for e1 in A: ! _* g1 t- ]! A for e2 in B:* _4 I1 q, n" C J, W4 K/ i
for e3 in A: 2 ], ]3 I+ d3 }7 D) x for e4 in B:' e# N3 b2 r+ l6 p+ s
lists.append([e1,e2,e3,e4])" a$ H5 P5 @6 Q4 H/ e7 u2 ^
minV = 28800 * q# f0 Q/ j, l) k4 M for i in range(len(lists)): - a2 \% Z- T( k c, A) e6 C+ T t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1], p N. F7 ?& u
if t<minV:2 _* F& n, O! @! o) n% [: C: r
minV = t3 u' P) G, e& m
index = i 3 A& q/ U! {7 o; H9 @1 g return lists[index][0] # 给定下一步的4步计算最优 $ i' T& o, ]5 E' A8 n0 H% c4 J0 x0 z. ^% n2 |
def forward5(state,isEmpty,currP): # 五步最优( l+ S( z# Q- T R- n
lists = []! l7 N/ S/ M6 z
""" 遍历所有的可能性 """) l. @3 T) t; N" P! f* v$ H& D
if currP in A: # 如果当前在第二道工序CNC的位置4 {6 F! E! s6 I9 x9 }4 ~
rgv = 1 : Q. U% I2 k; w$ [ M3 A# ^ for e1 in B: " a7 @' s2 i, r+ H- d; h9 G/ e for e2 in A: # G# ]9 a& V( j/ r9 _1 p7 E for e3 in B:- O% {1 @/ g/ k: {( B
for e4 in A:! Q: s4 e8 y: ?1 v& k0 K& X
for e5 in B: ; ^7 B3 W6 r. A2 @- ` lists.append([e1,e2,e3,e4,e5]) 7 u: C9 q0 g6 e9 v3 t" I else:! i; V" P' _3 g7 M# g. i
rgv = 0 3 o. R; }1 j7 K$ {$ c" A3 R for e1 in A: 6 M3 M; E: f# B: ? @" x i. j for e2 in B:( r) Y! x0 u# |9 H& _5 y: C% R+ K Q
for e3 in A:6 C: [, d+ Z3 B( W/ g# B. J
for e4 in B:$ Y, W& Y/ J0 G3 P
for e5 in A:3 k9 K+ z p ^9 S+ a ^ R
lists.append([e1,e2,e3,e4,e5]) . h A$ U$ U, \$ s$ q U minV = 28800 2 w6 m- b5 P* x1 W6 B for i in range(len(lists)): 5 i* k$ J: ?5 H+ _ t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1] # M( V" H3 c s8 Y9 C. W if t<minV:7 j& H% t& L3 O; X5 ]
minV = t 4 r8 L- K2 `; c# a h& Z. x index = i" R/ }3 P3 I0 D) v+ n3 R R/ r/ ^
return lists[index][0] # 给定下一步的5步计算最优 ( o2 A: G4 L# r8 _' ]8 L2 O3 e$ a6 V1 g( X) q# Y# j
def forward6(state,isEmpty,currP): # 六步最优. e6 e7 Z2 Y: D; D( o
lists = []/ q# I" Q; x( g
""" 遍历所有的可能性 """ , \1 P: z# k7 k$ P4 |+ B if currP in A: # 如果当前在第二道工序CNC的位置 $ p* W4 b/ J( p# o rgv = 1; _' k0 W. K6 y" s1 e; J
for e1 in B:/ I" f: H5 @ E8 F% ~
for e2 in A: S; j/ T g% E% m: Z1 h/ p
for e3 in B:/ V/ a7 O# `& k" @9 N1 H- d6 U6 ]
for e4 in A: 6 D# i! E# e! I, p2 _ for e5 in B: / `3 P" o1 I. p' T' X7 ]) l8 |, n for e6 in A:) x! @3 J7 [0 e& f9 |
lists.append([e1,e2,e3,e4,e5,e6])! y1 E) |$ {) ~' s* [" h
else: + Y# l& g! c9 k rgv = 0! w( i5 K: M) B* b
for e1 in A:* W2 f6 D9 Z& L* q& [" Y
for e2 in B:# E& d6 A: h- G6 L* p; d a
for e3 in A:6 D1 C* j% O8 b# g3 P
for e4 in B:5 e# h6 d( _5 I+ W, e& N" J
for e5 in A:) a: ]/ D! z) C$ A6 \$ I2 X8 X
for e6 in B: 7 f$ Z" {# D+ b& r lists.append([e1,e2,e3,e4,e5,e6]) 1 Y% m& {- t0 b3 |. n, Q minV = 28800 8 P: t& b' k6 T" V for i in range(len(lists)):. M$ X, f8 q1 e8 K% c* L6 s8 s
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1] & F) X! T2 ^! b& D. d" l& p if t<minV:% n' q3 k4 B$ i8 t
minV = t+ x. f- _$ n% w3 U3 ]) O/ J7 N
index = i, k! L" C3 Z& q
return lists[index][0] # 给定下一步的6步计算最优 ) k, h i8 u8 B3 j" s. Y6 g : a4 ]9 e3 p: ydef forward7(state,isEmpty,currP): # 七步最优 i! F/ w: T, K: t. H; e5 a
lists = [] 2 l# x- H. a- Y& z1 _ """ 遍历所有的可能性 """+ X4 ]7 I" e) J3 I5 M3 z
if currP in A: # 如果当前在第二道工序CNC的位置) I9 O! Y% R- U- s* ]
rgv = 1, B6 a, T; |3 O7 A
for e1 in B: & [+ f6 F! v+ w4 p z1 j P for e2 in A:7 u+ I. G5 n+ W3 D3 m& t' V
for e3 in B: ( F; ` P! V2 O7 Q/ L4 |# N for e4 in A: " i! ~& P. b% s1 n for e5 in B: . y2 D2 V1 }, C% ^7 n5 I- B( [ for e6 in A:5 G0 Q1 H/ b) _/ V( k; _5 J/ Z' n
for e7 in B: ' v. M( x7 I2 i& F$ }- q lists.append([e1,e2,e3,e4,e5,e6,e7]) i6 o7 s t& Z" o p
else:0 I" B- [! J( Y& W* }* E* b; Z. V
rgv = 0. D, n, G: [) F9 I% z- M
for e1 in A: $ }" x6 [# W3 n3 `! c) u5 ~5 \ for e2 in B: # G; @4 A* t3 q2 W$ `% S3 W5 U! t for e3 in A:5 Z- ^5 p3 X. N( v
for e4 in B:7 y$ h1 ?8 ?0 h& C0 u
for e5 in A:; L/ v5 x& J" a8 @$ W. a3 N
for e6 in B: * ]8 g7 l* m8 u$ i1 h2 M9 F for e7 in A:2 d; B) U6 }% X* x6 q% G
lists.append([e1,e2,e3,e4,e5,e6,e7])# e' f3 X% i0 @$ G+ t0 e! f
minV = 28800# ^5 v/ _; Q- f% g. Y! |& u
for i in range(len(lists)): 7 h f9 h; l( s9 A) `; a t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1] * j6 Y2 @1 x3 v if t<minV:, i9 ~7 ]) g+ c I% F0 n$ l; G7 z
minV = t 0 ^0 m% m* }1 S5 o index = i 1 x t' Y' X; h, } return lists[index][0] # 给定下一步的7步计算最优 3 y& N9 `8 |) m% ]# |$ ~& w1 g% Z" @
def forward8(state,isEmpty,currP): # 八步最优5 M. b; H2 U' K
lists = [] 1 K/ {; S ^8 `* N/ ` """ 遍历所有的可能性 """, k0 D3 |6 S# E9 f
if currP in A: # 如果当前在第二道工序CNC的位置 9 X3 f1 D* ~" x rgv = 1 + y! n1 W) s* v8 w! z for e1 in B:7 h4 ^0 c E! ^, v$ k# R5 r, K8 O! f
for e2 in A:, \) ~: s: t6 i" ]9 S+ [
for e3 in B:" \" g( T0 ]6 t J4 Z
for e4 in A: . J% B1 k4 O1 {. W" e% {' ~, J u7 h for e5 in B:9 |: q0 U' k! Y4 Q
for e6 in A:4 p7 ~ k4 v# a1 X# s4 f
for e7 in B: 5 a) ~; a8 w9 s% H for e8 in A:% W! B; t0 e8 ]; x; X- |3 u: Y- B/ C( u
lists.append([e1,e2,e3,e4,e5,e6,e7,e8])! c+ b) W& ?1 A0 C$ }
else:- f. n$ S1 E% K
rgv = 0 , w* ?( c& n. C2 L0 _ V7 q. z: P for e1 in A: 2 m; u% R, j* z for e2 in B: 6 r1 D4 n9 q* b& ]; q+ ? for e3 in A:+ x! ^) A& n+ @
for e4 in B:% s- `& [0 N' @3 p9 ~6 P
for e5 in A: 1 P; T8 h: w3 G% V for e6 in B:8 r/ m0 M9 I* x
for e7 in A: 5 O+ H2 q0 F4 x) X. \7 s4 P for e8 in B:6 R& P9 o2 d) T8 U$ b( M) E* G
lists.append([e1,e2,e3,e4,e5,e6,e7,e8])5 U+ T6 C) b1 O3 G6 g, f4 U9 }
minV = 28800 7 H% p9 y$ X$ C: m for i in range(len(lists)):1 b9 j) m( o/ N9 Z8 K
t = time_calc(lists,state[:],isEmpty[:],rgv,currP,0)[-1], _" @$ z [3 p5 ^+ C
if t<minV: , I( G3 W6 ~* \/ O minV = t ! N, x7 e+ r x4 i/ R index = i 6 j1 T; D8 T! M5 |; Y3 C4 ?4 b return lists[index][0] # 给定下一步的8步计算最优" t6 f8 L F" n" t
% p5 s9 B6 J0 F& `* h& L
def greedy(state,isEmpty,rgv,currP,total): # 贪婪算法 X3 Z0 v- t4 I4 ]- X9 p/ E1 Z line = [] 3 J1 l: ~3 y* ?: s' k4 \2 L count = 0 ' Y2 v, k! h+ C while True:4 s# F3 A/ k& N8 v
#nextP = forward4(state[:],isEmpty[:],currP) 7 ^' K! `+ ~! M8 C2 y
nextP = forward5(state[:],isEmpty[:],currP) 3 W2 k" k8 a. j5 w line.append(nextP) 6 q5 c. T$ v$ }& ` rgv,currP,t = time_calc([nextP],state,isEmpty,rgv,currP,0) 7 H/ Z4 L& U+ T2 n! T total += t5 {0 Q3 h6 S, y# w4 l
count += 12 k% J9 s7 `* B( i
if total>=28800:( I) p t- ?* b4 @' W1 N
break 3 P! H0 A! a: `. ?, ?- E. a return line' k2 \% v$ U$ n, Y+ X8 i$ g; U+ Y
. I4 ~* l7 ^8 I) {1 b9 S3 @
if __name__ == "__main__":( P7 t X% N0 X8 [3 i+ M( p0 U) t
state,isEmpty,log,count1,rgv,currP,total,seq = init_first_round() & M t1 ?& |7 f! E print(state,isEmpty,log,count1,rgv,currP,total,seq) ; W6 ?, J2 f) K4 X; l' e line = greedy(state[:],isEmpty[:],rgv,currP,total)( M# n, `' s! \
simulate(line,state,isEmpty,log,count1,rgv,currP,total) ' c( n" \- e: ? b# { * Y& S0 ]9 P: m& I9 I write_xlsx() # g1 K$ G) q& z3 Y4 r: T后记 7 v1 N( n- a4 d; z& |! M j! h' Z + Y! n2 `" p+ |) S这次博客有点赶,所以质量有点差,很多点没有具体说清楚。主要最近事情比较多。本来也没想写这篇博客,但是觉得人还是要善始善终,虽然没有人来阅读,但是学习的路上还是要多做小结,另外也是万一有需要的朋友也可以给一些参考。虽然我的水平很差劲,但是我希望能够通过交流学习提高更多人包括我自己的水平。不喜勿喷!: x4 r6 Y7 w o
--------------------- ; Y' ]3 r! |7 V+ [. a/ B% H - I l# Z4 G4 h% S/ a- G; A2 g* m0 M2 d' v) v/ S
e' I6 \6 s( q8 m; G' F 7 X l) X. G/ a6 b" U $ e6 u& K/ T9 s6 L1 D 0 Z* d8 a% e, T+ f! z; [# q% E# D& i: _1 T6 B
" w1 i, I5 b. j( b0 I9 s
9 c+ H$ p. K: z' ~