설명
이 모델은 컨테이너에 있는 상자의 최적 구성을 찾으려고 시도합니다. 두 물체의 3차원 측정값을 유지하면서 기하학적 제한. 모델은 순서를 결정하기 위해 다양한 방법을 사용합니다. 상자를 포장해야 하는 곳. 슬롯 나라 Connect는 br1.csv 파일에서 데이터를 읽는 데 사용됩니다. 데이터는 컨테이너 포장에 관한 Bischoff/Ratcliff 논문에서 나온 것입니다. ORLIB 인스턴스 컬렉션에서 사용할 수 있습니다.http://people.brunel.슬롯 나라uk/~mastjjb/jeb/orlib/thpackinfo.html
대형 모델 유형 :MIP
카테고리 : 슬롯 나라 모델 라이브러리
$title 상자 포장 문제(상자 포장,SEQ=434)
$onText
이 모델은 컨테이너 내 상자의 최적 구성을 찾으려고 시도합니다.
두 물체의 3차원 측정값을 유지하면서
기하학적 제한. 모델은 순서를 결정하기 위해 다양한 방법을 사용합니다.
상자를 포장해야 하는 곳. GAMS Connect는 br1.csv 파일에서 데이터를 읽는 데 사용됩니다.
데이터는 컨테이너 포장에 관한 Bischoff/Ratcliff 논문에서 나온 것입니다.
ORLIB 인스턴스 컬렉션(http://people.brunel.ac.uk/~mastjjb/jeb/orlib/thpackinfo.html)에서 사용할 수 있습니다.
이 공식은 다음에 자세히 설명되어 있습니다.
오클루, 발렌티나 & 푸겐슈, 아르민 & 파멘, 올리비에. (2020).
3D 컨테이너 포장 문제에 대한 새로운 수학적 모델. 10.26127/btuopen-5088.
키워드: 혼합 정수 선형 계획법, 컨테이너 패킹 문제,
3D-bin 포장 문제, 박스 포장 문제
$offText
$eolCom !!
$설정되지 않은 경우 DEBUG $set DEBUG 0 !! DEBUG=1은 추가 출력을 활성화합니다.
$METHOD를 설정하지 않은 경우 $set METHOD 일괄 처리 !! [표준, 탐욕, 배치]
$설정되지 않은 경우 FIXLOCDIM $set FIXLOCDIM 0 !! FIXLOCDIM=1은 컨테이너에 배치된 상자의 위치를 고정합니다.
$설정되지 않은 경우 MAXCOPIES $set MAXCOPIES 50 !! 박스 유형당 최대 복사본 수
$설정되지 않은 경우 BATCH_SIZE $set BATCH_SIZE 5 !! 배치당 상자 수
$설정되지 않은 경우 TIMELIMIT $set TIMELIMIT 30 !! 총 시간 제한
* 컨테이너의 3D 측정값을 정의합니다.
$설정되지 않은 경우 X_CONT $set X_CONT 587
$설정되지 않은 경우 Y_CONT $설정 Y_CONT 233
$설정되지 않은 경우 Z_CONT $set Z_CONT 220
* 원시 입력 데이터
box_id '입력 데이터 상자 ID' 설정
box_id_hdr '입력 데이터 헤더' / x, rot_x, y, rot_y, z, rot_z, nb, Weight/
mult_box '동일한 유형의 여러 상자에 대한 입력 데이터 상자 복사 ID 색인' / cp1*cp%MAXCOPIES% /;
매개변수
box_data(box_id<, box_id_hdr)
희미한_raw(box_id,box_id_hdr);
* 데이터 읽기
$onEmbeddedCode 연결:
- CSV리더:
파일: br1.csv
이름: box_data
헤더: 참
indexColumns: 1
valueColumns: "2:lastCol"
- GAMS작성기:
기호: 모두
$offEmbeddedCode
* 상자 수를 줄이고,
* 전체 규모 문제는 계산적으로 어려워진다
box_data(box_id, 'nb') = ceil(box_data(box_id, 'nb')/2.5);
표시$%DEBUG% box_data
$eval MAXB 카드(box_id)*%MAXCOPIES%
* 원시 데이터 일관성 검사
abort$[smax(box_id, box_data(box_id, 'nb')) > %MAXCOPIES%] '입력 데이터에 지원되는 것보다 더 많은 상자 복사본이 포함되어 있습니다. MAXCOPIES 늘리기';
* 내부 데이터 구조
Set bb 슈퍼 박스 세트 / b1*b%MAXB%, vbox 'virtual box' /
b_exist(bb) 기존 상자 세트
b(bb) 상자의 동적 하위 집합
bmap(box_id,mult_box,bb) 복사 ID가 있는 입력 데이터 상자 ID를 내부 상자 ID로 매핑
bmap_red(bb,box_id) 입력 데이터 상자 ID를 내부 상자 ID로 매핑
d(box_id_hdr) 치수 / x, y, z /
r(box_id_hdr) 상자 회전 가능성 / rot_x, rot_y, rot_z /
o 상자의 6가지 가능한 방향 / o1*o6 /
입력 차원과 방향 차원의 매핑을 정의하는 rmap(o,d,d) 회전
/ o1.(x.x,y.y,z.z) 'x->x y->y z->z를 입력하세요'
o2.(x.x,y.z,z.y) 'x 축을 따라 입력을 90도 회전 x->x y->z z->y (rot_x = 0인 경우 불가능)'
o3.(x.z,y.y,z.x) 'y 축을 따라 입력을 90도 회전 x->z y->y z->x (rot_y = 0인 경우 불가능)'
o4.(x.y,y.x,z.z) 'z 축을 따라 입력을 90도 회전 x->y y->x z->z (rot_z = 0인 경우 불가능)'
o5.(x.z,y.x,z.y) 'x+z 축을 따라 입력을 90도 회전 x->z y->x z->y (rot_x = 0 또는 rot_z = 0인 경우 불가능)'
o6.(x.y,y.z,z.x) 'x+y 축을 따라 입력을 90도 회전 x->y y->z z->x (rot_x = 0 또는 rot_y = 0인 경우 불가능)' /
ro(r,o) 회전 제한 / rot_x.(o2,o5,o6), rot_y.(o3,o6), rot_z.(o4,o5) /
슬롯 나라(bb,o) 사용 가능한 방향 / #bb.#o /;
별칭 (bb,bb1,bb2), (b,b1,b2), (d,d1);
매개변수
희미한_cont(d) '컨테이너 크기' / x %X_CONT%, y %Y_CONT%, z %Z_CONT% /
희미한_o(bb,o,d) '방향 o에 대한 상자 bb의 크기'
rot(bb, r) '허용된 회전'
Box_vol(bb) '각 상자의 부피';
* 원시 상자 ID를 내부 상자 ID에 매핑
b('b1') = 예;
루프((box_id,mult_box)$[ord(mult_box) <= box_data(box_id,'nb')],
bmap(box_id,mult_box,b) = 예;
b(bb) = b(bb-1);
);
옵션 클리어=b;
옵션 bmap_red<bmap, b_exist<bmap;
* 모든 회전에 대한 상자 크기 계산
Dim_o(bb,o,d) = sum((bmap_red(bb,box_id),rmap(o,d1,d)), box_data(box_id,d1));
* 사용 가능한 회전 계산
rot(bb, r) = sum(bmap_red(bb,box_id), box_data(box_id, r));
* 각 상자의 부피를 m3으로 확장하여 계산합니다.
Box_vol(bb) = prod(d, 희미한_o(bb,'o1', d)/100);
* 회전 제한으로 인해 상자의 불가능한 방향을 비활성화합니다.
loop(r, 슬롯 나라(bb,o)$(ro(r,o) 및 rot(bb,r)) = no);
바이너리 변수
OMEGA(bb) '컨테이너에 있는 상자(1) 여부(0)'
ALPHA(bb,o) '방향이 o (1)이거나 (0)이 아닌 컨테이너에 있는 상자'
RELPOS(bb,bb,d) '상대 위치: 첫 번째 상자 위치 + 치수 <= 두 번째 상자 위치인 경우 1';
음수가 아닌 변수
LOC(bb,d) '(x,y,z) 컨테이너에 있는 bb의 왼쪽 하단 모서리 위치'
DIM(bb,d) '(x,y,z) 방향을 고려한 컨테이너에 있는 상자 bb의 크기';
변수
VOL '목표 값 - 컨테이너에 있는 모든 상자의 총 부피';
방정식
eq_def_DIM(bb,d) '방향을 고려하여 컨테이너의 상자 크기 정의'
eq_커플링_ALPHA_OMEGA(bb) '컨테이너의 상자에 대해서만 방향 선택'
eq_inside_container(bb,d) '컨테이너 크기 존중'
eq_deactivate_RELPOS(bb,bb,d) 'RELPOS는 컨테이너의 첫 번째 상자인 경우 0이 아닌 값만 사용해야 합니다.'
eq_no_overlap(bb,bb, d) '컨테이너의 상자는 겹쳐서는 안 됩니다.'
eq_def_RELPOS(bb,bb) 'RELPOS 정의, 즉 첫 번째 상자 왼쪽/뒤/아래 두 번째 상자 (1), 그렇지 않으면 (0)'
eq_def_VOL '목적 함수 - 컨테이너의 볼륨 활용도 극대화';
* (23/24/25) [숫자는 논문의 방정식 번호와 일치합니다]
eq_def_DIM(b,d)$[not sameas(b,'vbox')].. DIM(b,d) =e= sum(o, 희미한_o(b,o,d)*ALPHA(b,o));
* (26)
eq_connect_ALPHA_OMEGA(b)$[not sameas(b,'vbox')].. sum(슬롯 나라(b,o), ALPHA(b,o)) =e= OMEGA(b);
* (27 a/b/c)
eq_inside_container(b,d).. LOC(b,d) + DIM(b,d) =l= 희미한_cont(d) * OMEGA(b);
* (28 a/b/c)
eq_deactivate_RELPOS(b1(bb1),b2(bb2),d)$[ord(bb1)<ord(bb2)].. RELPOS(b1,b2,d) + RELPOS(b2,b1,d) =l= OMEGA(b1);
* (29)
eq_def_RELPOS(b1(bb1),b2(bb2))$[ord(bb1)<ord(bb2)].. sum(d, RELPOS(b1,b2,d) + RELPOS(b2,b1,d)) =g= OMEGA(b1) + OMEGA(b2) - 1;
* (30 a/b/c)
eq_no_overlap(b1,b2,d)$[not sameas(b1,b2)].. LOC(b1,d) + DIM(b1,d) =l= LOC(b2,d) + 희미한_cont(d)*(1-RELPOS(b1,b2,d));
* (31)
eq_def_VOL.. VOL =e= sum(b, Box_vol(b)*OMEGA(b));
모델 cpp / 모두 /;
cpp.reslim = %TIMELIMIT%;
$ifThenI %system.mip%==cplex
* Cplex 옵션 파일 생성
$$onEcho > cplex.opt
해결 최종 0
밉스타트 1
$$off에코
* 옵션 파일 사용
cpp.opt파일 = 1;
$elseIfI %system.mip%==구로비
* 구로비 옵션 파일 생성
$$onEcho > gurobi.opt
해결 고정 0
밉스타트 1
norelheurtime %TIMELIMIT%
$$off에코
* 옵션 파일 사용
cpp.opt파일 = 1;
$endIf
스칼라 num_of_bat;
num_of_bat = ceil(카드(b_exist)/%BATCH_SIZE%);
옵션 limrow=0, limcol=0, solprint=off,solvlink=5;
$ifE %DEBUG%==1 옵션 limrow=1e6, limcol=1e6, solprint=on;
* 기존의 모든 상자를 한 번에 해결
$ifThenI.방법 %METHOD%==표준
b(b_exist) = 예;
cpp max VOL은 MIP를 사용하여 해결합니다.
* 각 상자에 대해 반복적으로 해결
$elseIfI.method %METHOD%==탐욕스러운
루프(bb$b_exist(bb),
b(bb) = 그렇습니다;
cpp max VOL은 MIP를 사용하여 해결합니다.
OMEGA.fx(bb) = 라운드(OMEGA.l(bb));
$$ifE %FIXLOCDIM%=1 ALPHA.fx(bb,o) = round(ALPHA.l(bb,o)); LOC.fx(bb,d) = LOC.l(bb,d); DIM.fx(bb,d) = DIM.l(bb,d);
);
* n개의 상자를 일괄 처리하고 모델을 해결합니다.
$elseIfI.method %METHOD%==배치
스칼라 i;
for(i = 1 ~ num_of_bat,
b(bb)$(ord(bb) <= %BATCH_SIZE%*i) = 예;
cpp max VOL은 MIP를 사용하여 해결합니다.
OMEGA.fx(b) = 라운드(OMEGA.l(b));
$$ifE %FIXLOCDIM%=1 ALPHA.fx(b,o) = round(ALPHA.l(b,o)); LOC.fx(b,d) = LOC.1(b,d); DIM.fx(b,d) = DIM.l(b,d);
);
$endIf.방법
매개변수 담당자(*) 보고서;
rep('총 상자 수') = 카드(b_exist);
rep('컨테이너에 있는 상자 수') = sum(b_exist, OMEGA.l(b_exist));
rep('컨테이너의 부피 [m3]') = prod(d, 희미한_cont(d)/100);
rep('가장 작은 상자의 부피 [m3]') = smin(b_exist, Box_vol(b_exist));
rep('가장 큰 상자의 부피 [m3]') = smax(b_exist, Box_vol(b_exist));
rep('모든 상자의 총 부피 [m3]') = sum(b_exist, Box_vol(b_exist));
rep('컨테이너에 있는 상자의 총 부피 [m3]') = sum(b_exist, Box_vol(b_exist)*OMEGA.L(b_exist));
rep('컨테이너에 있는 상자의 비율') = (rep('컨테이너에 있는 상자의 수') / rep('총 상자의 수'));
rep('컨테이너에 들어 있는 상자의 총 부피 비율') = (rep('컨테이너에 들어 있는 상자의 총 부피 [m3]') / rep('모든 상자의 총 부피 [m3]'));
rep('사용된 컨테이너 부피 비율') = (rep('컨테이너에 들어 있는 상자의 총 부피 [m3]') / rep('컨테이너의 부피 [m3]'));
옵션 담당자:2:0:1; 디스플레이 담당자;