さまざまな入力に対して妥当な結果が得られるソリューションを見つけました。最初にモデルを適合させます。1 回目は制約の下端に、もう 1 つは上端に合わせます。これら 2 つの近似関数の平均を「理想関数」と呼びます。この理想的な関数を使用して、制約が終了する場所の左右を外挿し、制約内のギャップ間を補間します。すべての制約を含め、理想的な関数の値を一定の間隔で計算します。左側の関数がほぼ 0 の場所から、右側のほぼ 1 の場所までです。制約では、制約を満たすために必要に応じてこれらの値をクリップします。最後に、これらの値を処理する補間関数を作成します。
私の Mathematica の実装は次のとおりです。
まず、いくつかのヘルパー関数:
(* Distance from x to the nearest member of list l. *)
listdist[x_, l_List] := Min[Abs[x - #] & /@ l]
(* Return a value x for the variable var such that expr/.var->x is at least (or
at most, if dir is -1) t. *)
invertish[expr_, var_, t_, dir_:1] := Module[{x = dir},
While[dir*(expr /. var -> x) < dir*t, x *= 2];
x]
そして、ここに主な機能があります:
(* Return a non-decreasing interpolating function that maps from the
reals to [0,1] and that is as close as possible to expr[var] without
violating the given constraints (a list of {x,ymin,ymax} triples).
The model, expr, will have free parameters, params, so first do a
model fit to choose the parameters to satisfy the constraints as well
as possible. *)
cfit[constraints_, expr_, params_, var_] :=
Block[{xlist,bots,tops,loparams,hiparams,lofit,hifit,xmin,xmax,gap,aug,bests},
xlist = First /@ constraints;
bots = Most /@ constraints; (* bottom points of the constraints *)
tops = constraints /. {x_, _, ymax_} -> {x, ymax};
(* fit a model to the lower bounds of the constraints, and
to the upper bounds *)
loparams = FindFit[bots, expr, params, var];
hiparams = FindFit[tops, expr, params, var];
lofit[z_] = (expr /. loparams /. var -> z);
hifit[z_] = (expr /. hiparams /. var -> z);
(* find x-values where the fitted function is very close to 0 and to 1 *)
{xmin, xmax} = {
Min@Append[xlist, invertish[expr /. hiparams, var, 10^-6, -1]],
Max@Append[xlist, invertish[expr /. loparams, var, 1-10^-6]]};
(* the smallest gap between x-values in constraints *)
gap = Min[(#2 - #1 &) @@@ Partition[Sort[xlist], 2, 1]];
(* augment the constraints to fill in any gaps and extrapolate so there are
constraints everywhere from where the function is almost 0 to where it's
almost 1 *)
aug = SortBy[Join[constraints, Select[Table[{x, lofit[x], hifit[x]},
{x, xmin,xmax, gap}],
listdist[#[[1]],xlist]>gap&]], First];
(* pick a y-value from each constraint that is as close as possible to
the mean of lofit and hifit *)
bests = ({#1, Clip[(lofit[#1] + hifit[#1])/2, {#2, #3}]} &) @@@ aug;
Interpolation[bests, InterpolationOrder -> 3]]
たとえば、対数正規関数、正規関数、またはロジスティック関数に適合させることができます。
g1 = cfit[constraints, CDF[LogNormalDistribution[mu,sigma], z], {mu,sigma}, z]
g2 = cfit[constraints, CDF[NormalDistribution[mu,sigma], z], {mu,sigma}, z]
g3 = cfit[constraints, 1/(1 + c*Exp[-k*z]), {c,k}, z]
例の制約の元のリストでは、これらがどのように見えるかを次に示します。
(ソース: yootles.com )
正規とロジスティックはほぼ重なり合っており、対数正規は青い曲線です。
これらは完全ではありません。特に、それらは完全に単調ではありません。導関数のプロットは次のとおりです。
Plot[{g1'[x], g2'[x], g3'[x]}, {x, 0, 10}]
(ソース: yootles.com )
これは、滑らかさの欠如と、ゼロに近いわずかな非単調性を示しています。このソリューションの改善を歓迎します!