[Inserted Image]

『Global Optimization Toolbox による最適化』
数式処理システム Maple で動く実践的最適化アプリケーション

Maple 上での“最適な”形状設計

ある化粧品メーカーでは、規定容量の香水を入れられ、かつ輸送コストを抑えることのできる新商品の香水ボトルを設計する必要が出てきました。輸送コストをある程度抑えるには香水ボトルを梱包する箱を十分小さくする必要があります。また、それでいてアピール度のある形状を設計しなければなりません。

協議の結果、ボトルの基本形状は薄型の楕円形とすることになりました。つまり、楕円型形状を表すモデル

x^2/(a^2)+y^2/(b^2)+z^2/(c^2) = 1

の各係数 a, b, c に加え、楕円型を適当な高さで切るためのパラメータ h を考えます。

ボトル形状の設計

ボトルの基本形状は原点を中心とした楕円形状とします。変数 bottleShape に楕円型を表す基本式を設定します;

> bottleShape := x^2/a^2 + y^2/b^2 + z^2/c^2 = 1;

bottleShape := x^2/a^2+y^2/b^2+z^2/c^2 = 1

なお、z 軸方向での高さは楕円自体の頂点座標としますが、底面の位置は平面 z = -h までとします。適当な係数値でこの形状を描画してみます。

> with(plots):

> implicitplot3d(
 eval(bottleShape, {a=2, b=1.5, c=1}),
 x=-2..2, y=-1.5..1.5, z=-6/10..1,
 scaling=constrained, style=patchcontour,
 axes=frame, orientation=[122,60]
);

[Plot]

このグラフィックスの描画では、底面は z = -6/10 までとしていることに注意してください。

目的関数の設定

この問題における目的関数は、幅 2a cm, 奥行き 2b cm でスプレーポンプ部分の高さ c も考慮した高さ c+h+1 cm の香水ボトルを梱包する箱の容量を可能な限り小さくすることです。すなわち、

> packageVolume := (2*a) * (2*b) * (c + h + 1);

packageVolume := 4*a*b*(c+h+1)

を十分小さくすることです。

制約条件の設定

ボトルの形状に関して、いくつかの制約条件を設定していきます。

制約条件1:香水ボトルの容量

香水ボトルは最低でも 40ml の容量を蓄えられなければなりません。ボトルの体積は、原点における楕円の面積を用いて以下で表すことができます;

> z_cross := Pi * a * b * (1 - z^2/c^2);

z_cross := Pi*a*b*(1-z^2/c^2)

変数 z で表されるこの断面積の関数が、z = -h から z = c まで動いたときの体積は積分により以下にして求められます。

> vol := Int( z_cross, z=-h..c);

vol := Int(Pi*a*b*(1-z^2/c^2), z = -h .. c)

> bottleVolume := value(vol);

bottleVolume := -1/3*Pi*a*b*(c^3+h^3)/c^2+Pi*a*b*(c+h)

体積は 40ml 以上ですので制約条件式は以下になります。

> const1 := bottleVolume >= 40;

const1 := 40 <= -1/3*Pi*a*b*(c^3+h^3)/c^2+Pi*a*b*(c+h)

>

制約条件2:底面の大きさ

香水ボトルを陳列棚に安定して置けるようにするため、底面は最低でも直径 2cm の大きさが必要になります。底面 z = -h における直径の最小値は、変数 h を用いて

2*sqrt(b^2*(1-h^2/(c^2)))

で与えられます。最低でも直径 2cm ですので、以下の式で与えられる h^2 の値が直径となります;

> hsquare := solve( 2*sqrt(b^2*(1-h^2/c^2))=2, h^2 );

hsquare := c^2*(b^2-1)/b^2

従って制約条件は、

> const2 := h^2 <= hsquare;

const2 := h^2 <= c^2*(b^2-1)/b^2

となります。

>

制約条件3:美的な形状

この香水の購買ターゲットの傾向として、流線型の形状を好むことがわかっています。形状に対する制約条件として係数 a, b に対して以下を設定しておきます。

> const3 := 2*b <= a;

const3 := 2*b <= a

以上で、すべての制約条件が揃いました。

最適形状を求める

ボトルの形状や容量などの制約条件のもとで、最適化を実施します。

> with(GlobalOptimization);

[GlobalSolve, Interactive]

> const_all := {const1, const2, const3};

const_all := {h^2 <= c^2*(b^2-1)/b^2, 2*b <= a, 40 <= -1/3*Pi*a*b*(c^3+h^3)/c^2+Pi*a*b*(c+h)}

> solution :=
GlobalSolve(
 packageVolume,
 const_all,
 a=1..10, b=1..10, c=1..10, h=1..10,
 feasibilitytolerance=10^(-8)
);

solution := [77.6889319085823190, [c = 5.38629351673990352, b = 1.07647913913670790, a = 2.15295827827341580, h = 1.99397486656431466]]

ここで、solution の一番目の結果が香水ボトルの容量となります。

形状を描画

最適化が施されたので、まず求まった係数が制約条件を満たしているかどうかを確認するため、誤差値を計算してみます。

> const_err := map(x->abs(rhs(x)-lhs(x)), const_all);

const_err := {abs(c^2*(b^2-1)/b^2-h^2), abs(-a+2*b), abs(-1/3*Pi*a*b*(c^3+h^3)/c^2+Pi*a*b*(c+h)-40)}

> evalf(subs(solution[2], const_err));

{0., 0.99367056281e-8, 0.4402325982e-8}

いずれも十分小さい誤差であることがわかります。

さて、求められた係数値によりボトル形状を描画してみます。

> newBottle := eval(bottleShape, solution[2]);

newBottle := .21573905516336355393*x^2+.86295622065345421573*y^2+0.34468308259690090611e-1*z^2 = 1

描画範囲も計算された最適係数から適当な変数に割り当てておきます。

> range_a := eval(a, solution[2]):
range_b := eval(b, solution[2]):
range_c := eval(c, solution[2]):
h_value := eval(h, solution[2]):

> with(plottools):

> body :=
implicitplot3d(
 newBottle,
 x=-range_a..range_a, y=-range_b..range_b, z=-h_value..range_c,
 color=gold, style=patchcontour,
 transparency=0.5
):
cap :=
cylinder([0,0,0.95*range_c], range_a/6, color=grey):

> display(
 [body, cap],
 scaling=constrained,
 axes=frame,
 orientation=[121,60]
);

[Plot]