Open dreeves opened 2 years ago
I don't think this works but for brainstorming:
Suppose the user specified two constants -- a
and b
-- and the PPR were a*r+b
.
The UI wouldn't have to be like "please choose a slope and y-intercept for your PPR function" (which would be a bit much even for Beeminder users) but could be like "choose either an absolute PPR or specify it as a fraction of your daily commitment amount". That's understandable enough and just imposes an additional constraint via the UI that either a
or b
has to be 0 but Beebrain needn't care about that.
Except a PPR of a*r+0
doesn't work when the slope is zero. That's why we added that ugly absolute 2 gunits. Forcing the user to pick both a
and b
nonzero is also not great.
I feel like the inelegance here means we need to rethink PPRs at a deeper level...
Even things like "daily commitment amount" are not super straight-forward when used over time, rather than instantaneously.
What if there's a rate that changes? How about weekends off? Not even from a programming perspective--as a user, I would have no idea how to predict what would happen when I put a number in there other than to just try it.
Another brainstorming proposal to at least mitigate the grossness of the "absolute 2 gunits" thing is to treat that as an explicit user-chosen parameter. Hypothetical microcopy:
For do-less goals, Beeminder never presumes you did nothing if you don't report how much you did. Whatever your daily commitment, Beeminder pessimistically presumes you did twice that much if you don't enter a datapoint. Of course that doesn't work if your commitment is zero (which we don't recommend). In that case please specify how much Beeminder should presume: ____
And now that I say that, what about just enforcing strictly positive slopes on do-less graphs? You'd have to approximate do-zero with do-0.0001-per-day or something. Effectively do-zero but the PPRs would need no special case. And I don't know of any use case for negative slope segments of a do-less graph but user-mary may. We can start by seeing how plangently user-mary screams?
Related use case: An inbox whittle-down goal where you want to allow your messages to jump back up while on vacation. Or the classic all-you-can-eat-buffet-hopping vacation with weight loss. These aren't do-less goals though.
If there are important use cases that enforced strictly monotone do-less graphs would break, maybe they could be handled by True Breaks?
What if there's a rate that changes?
The rate always means the current slope of the red line.
How about weekends off?
For do-less, those are just steep sections, so I think there's no special case to worry about with weekends-off.
as a user, I would have no idea how to predict what would happen when I put a number in there
Yeah, sounds true and like a big red flag. (As if add a parameter wasn't red flag enough!)
I'm now liking my proposal of disallowing exactly-zero or negative sloped segments. We do still need vertical segments to implement ratcheting of do-less goals. At least until we have True Breaks. But I believe vertical segments aren't a monkey wrench for isolines. I believe the slope of every point on the red line is well-defined as the limit of the slope from the right. Or is it left? Either way, vertical jumps should be fine?
PS: Staring at the code, I think "from the right" is correct. If there's a kink in the red line at time t, the slope at t is defined as the upcoming slope.
Back in the day when we were discussing this, I had recommended *ppr = min(2slope, daily_min),** which (maybe) is more understandable than an arbitrary linear function and would disallow loopholes if daily_min is forced to be above some epsilon. Disallowing horizontal segments is not quite a solution since one can always create an almost horizontal section, which would have negligible ppr due to the small slope.
Huge thanks to Uluc for coming up with a much nicer PPR function. I've further streamlined it and generalized it, I think.
Originally I had a bunch of the following in the top-level comment of this gissue but am moving it here.
The status quo ante PPR function for drawing isolines on do-less graphs was like so:
r === 0 ? -yaw*2 : // absolute PPR of 2 gunits if flat slope
r*yaw > 0 ? 0 : // flatline if the line is sloping the wrong way
2*r // normally PPR at twice the daily rate
where r
is the slope of the bright red line in goal units per day.
That's pretty ugly! Especially that special case of an arbitrary "2 goal units" when the slope is flat. A jump of 2 goal units could be huge or trivial depending on the goal! Also the discontinuities are not nice for drawing isolines.
Here are two alternative proposals from Uluc, where d
is a user-chosen minimum PPR and r
is still the daily slope of the red line.
yaw < 0 && r > 0 ? max(d, 2*r) : // PPR of twice daily rate but at least d
yaw >= 0 && r > 0 ? min(d, 2*r) : // (flip it around for RASH goals)
-d < r && r <= 0 ? d+r : // make PPR decay smoothly to zero
0
yaw>0 ? min(0, d+r) : // Negative (or zero) PPRs for do-more and rationing
max(0, d+r) // Positive (or zero) PPRs for do-less and weight/inbox
Both options A and B ensure that you lose at least the amount d
of safety buffer every day. Option B is such that you always lose exactly that much for positive slopes, whereas option A loses higher amounts of buffer for larger slopes in proportion to the slope itself.
Here's some tentative documentation-driven development for transitioning to Option B and explaining the dailymin parameter to users:
"Minimum PPR: ____ (This is a lower bound on how much Beeminder automatically presumes you did if you fail to report data. This is an anti-cranial-silicosis measure. It's crucial that you not be able to ignore a Beeminder goal. For a do-less goal like this, that means there have to be consequences for not entering data. Note that this minimum PPR is in addition to whatever the daily rate is.)"
[if user enters 0 or a number with the same sign as yaw: "Error: The minimum PPR must be enough to eventually derail you, i.e., {yaw<0 ? 'greater than' : 'less than'} zero"]
We can do much better than the above webcopy but it's convincing me that this is in fact explainable. Or the UI could be fancier and show dynamically what the actual PPR will be for the user's choice of dailymin and the current daily rate.
Transition idea: We create this field (wants a better name than dailymin -- let's call it d
for now) and pre-populate it with whatever the graph's current daily rate is. Like the day we do the database update query, d
becomes set to what the daily rate is on that day. That makes it match the status quo until the person's rate changes. Then we explain to them that they can adjust that d
parameter.
Of course this seems to violate the anti-settings principle but, first of all, look at how much cleaner Option B is than Option A! [UPDATE: I no longer think that.] And second, it doesn't really even violate anti-settings if we just generalize the existing maxflux parameter for weight loss goals (which also solves a Massive Problem we have with weight loss goals)...
"you're losing weight? ok, how much does your weight fluctuate day-to-day? the bigger number you give the more initial safety buffer you'll have, cuz we'll draw your red line that much above your current weight, but also whatever number you give, we'll pessimistically presume your weight increased by that much on any day you don't report your weight!"
"you want to eat less sugar? ok, how much do you want to eat per day? great, and if you don't report, how much more than that daily amount should we pessimistically presume you ate?"
The above cases are in fact instances of the same general rule, Option B. We're getting the parameter d
from the user regardless. For weight loss we call it maxflux. For sugar-eating we call it something like "minimum PPR". Regardless, the actual PPR datapoint is always r+d
-- the daily rate plus d
. As long as d
has the opposite sign as yaw, we achieve the invariant that the PPRs always eventually derail you.
Another possibility for the user-specified daily value would be to ask for "maximum number of days allowed without data". With this, we have d=safetybuf/numdays where the safetybuf is the difference between the latest datapoint value and the redline, and numdays is the selected setting. This could be much more intuitive, in my opinion.
(Core ideas here by Uluc, rewritten by Dreev.)
Old PPR function:
New PPR function:
(Or equivalently, if more opaquely:
yaw * min(yaw*D, yaw*2*r)
)where D (aka "daily min") is a new user-chosen parameter giving a minimum PPR. This could generalize maxflux and would let us use a consistent PPR function for all goal types. Note that setting D=0 for do-more goals gives the expected PPR=0 for that case.
Spelling out the different cases just to get a feel for it:
Potential problem: all-you-can-eat-buffet-hopping vacations. If you are intentionally taking a break on a weight-loss goal and having the red line slope up for a while then that's yaw<0 and r>0 which means PPRs of at least 2r. Probably you don't want that? Maybe we just assume that the right answer to that is True Breaks (gaps in the red line when you schedule a break).
Cognata
205
151
110
237
Verbata: isolines, graph aesthetics, PPR function, pessimistic presumptive reports, universal PPR, true breaks, settings vs anti-settings,