Я нашел решение, которое дает разумные результаты для различных входов.
Я начинаю с подгонки модели - сначала к нижним пределам ограничений, а затем к верхним.
Я буду называть среднее значение этих двух встроенных функций «идеальной функцией».
Я использую эту идеальную функцию для экстраполяции слева и справа от того, где заканчиваются ограничения, а также для интерполяции между любыми пропусками в ограничениях.
Я вычисляю значения для идеальной функции через равные промежутки времени, включая все ограничения, от того, где функция почти равна нулю слева, до почти одного справа.
При ограничениях я обрезаю эти значения по мере необходимости, чтобы удовлетворить ограничениям.
Наконец, я создаю интерполяционную функцию, которая проходит через эти значения.
Моя реализация 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]
Вот как это выглядит для моего первоначального списка примеров ограничений:
ограниченное соответствие логнормальной, нормальной и логистической функции http://yootles.com/outbox/cdffit5.png
Норма и логистика почти друг на друга, а логнормал - синяя кривая.
Это не совсем идеально.
В частности, они не совсем однообразные.
Вот сюжет производных:
Plot[{g1'[x], g2'[x], g3'[x]}, {x, 0, 10}]
производные встроенных функций http://yootles.com/outbox/cdffit6.png
Это показывает некоторое отсутствие гладкости, а также небольшую немонотонность вблизи нуля.
Я приветствую улучшения этого решения!