I found a solution that gives reasonable results for various inputs. I will start by fitting the model - once to the lower limits of the constraints, and again to the upper limits. I will call the average of these two built-in functions an “ideal function”. I use this ideal function to extrapolate to the left and right of where the constraints end, and also to interpolate between any gaps in the constraints. I calculate values for an ideal function at regular intervals, including all restrictions, starting from the point where the function is almost zero on the left and ending with almost one on the right. With restrictions, I trim these values as needed to satisfy the restrictions. Finally, I create an interpolation function that goes through these values.
My implementation of Mathematica is as follows.
Firstly, a couple of helper functions:
(* Distance from x to the nearest member of list l. *) listdist[x_, l_List] := Min[Abs[x -
And here is the main function:
(* 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[(
For example, we can correspond to a lognormal, normal, or logistic function:
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]
Here's what they look like for my initial list of restrictions:

(source: yootles.com )
Normal and logistics are almost on top of each other, and the logarithm is a blue curve.
This is not quite perfect. In particular, they are not completely monotonous. Here is a plot about derivatives:
Plot[{g1'[x], g2'[x], g3'[x]}, {x, 0, 10}]

(source: yootles.com )
This shows some lack of smoothness, as well as a slight nonmonotonicity near zero. I welcome the improvements to this solution!