Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New growth rate handles #383

Merged
merged 17 commits into from
Oct 14, 2015
Merged

New growth rate handles #383

merged 17 commits into from
Oct 14, 2015

Conversation

Amy-Xu
Copy link
Member

@Amy-Xu Amy-Xu commented Oct 11, 2015

In this PR, all the growth rate handles are refactored as the new class style in #367. In terms of functionality, this PR is equivalent to #368, which can be closed after this PR's open. Similar to the Behavior class, this Growth class would copy both the baseline and reform calculators and apply user-specified rate on both calculators. A quick demo in a notebook is as follows:

screen shot 2015-10-11 at 6 47 14 pm

This is an example changing the general economic growth rate to 4%, in real terms, for both baseline and reform (add surtax on Itemized Deduction Benefits).

Without changing the growth rates:
Baseline:
screen shot 2015-10-11 at 6 44 47 pm

Reform:
screen shot 2015-10-11 at 6 44 59 pm

Increase general economic growth to 4% a year
Baseline:
screen shot 2015-10-11 at 6 45 19 pm

Reform:
screen shot 2015-10-11 at 6 45 30 pm

Haven't been able to change the algebra of growth rates for webapp yet.

@MattHJensen
Copy link
Contributor

@Amy-Xu, sounds like calling these things during increment_year() are fine. Just on the phone with @talumbau. He might provide some more detail soon.

if isinstance(growth, Growth):
self.growth = growth
else:
self.growth = Growth(start_year=policy.start_year)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. this idiom seems bad to me (used for both Growth and Behavior). If someone passes a Growth object for growth, then we set it to self.growth. If they pass anything else (a string, some other kind of object, whatever), we just silently make a new Growth object and assign it to self.growth. Basically the user could assume he/she is sending in an object for growth but actually ending up with something else (with no error/warning message). That seems bad. How about something like this?

if growth:
    if isinstance(growth, Growth):
        self.growth = growth
    else:
        raise ValueError("Must supply growth as a Growth object")
else:
    self.growth = Growth(start_year=policy.start_year

@Amy-Xu
Copy link
Member Author

Amy-Xu commented Oct 12, 2015

@talumbau Thanks! Will fix those very soon. I got very confused that Travis CI keeps telling me it cannot find that growth.json even thought all my local tests are passing. Could you take a glance of that error?

@MattHJensen
Copy link
Contributor

@talumbau Thanks! Will fix those very soon. I got very confused that Travis CI keeps telling me it cannot find that growth.json even thought all my local tests are passing. Could you take a glance of that error?

Try adding growth.json to MANIFEST.in

@talumbau
Copy link
Member

yes, I agree with @MattHJensen, I believe that adding it to the MANIFEST.in will put it in the egg file so that it can be read when running via Travis CI.

@@ -0,0 +1,26 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Amy-Xu could you take a crack at filling these in? Here is a suggestion, although please feel free to modify these.

long_name: "Deviation from CBO forecast of baseline economic growth (percentage point)"

description: "The data underlying this model are extrapolated to roughly match the CBO's projection of the economy's development over the 10-year federal budget window, with each type of economic data extrapolated at a different growth rate. This parameter allows a factor to be subtracted or added to those growth rates for the construction of the economic baseline. For example if you supply .02 (or 2%), then 0.02 will be added to the wage and salary growth rate, interest income growth rate, dividend growth rate, schedule E income growth rate, and all other growth rates used to extrapolate the underlying dataset."

long_name: "Replacement for CBO real GDP growth in economic baseline (percent)".

description: "The data underlying this model are extrapolated to roughly match the CBO's projection of the economy's development over the 10-year federal budget window, with each type of economic data extrapolated at a different growth rate. One of the growth rates taken from the CBO is GDP growth. This parameter allows you to specify a real GDP growth rate, and all other rates will be modified to maintain the distance between them and GDP growth in the CBO baseline. For example, if the CBO growth rate for one year is 0.02 and the user enters 0.018 for this parameter, then 0.002 will be subtracted from every growth rate in the construction of the economic baseline, including wage and salary growth, interest income growth, dividend growth, and many others.

cc @feenberg @martinholmer

@Amy-Xu
Copy link
Member Author

Amy-Xu commented Oct 13, 2015

I changed the application of adjustment and targets. More detailed description can be found in growth.json description node. Here are the tables after applying adjustments or targets. Default results remain the same.

GDP growth (real terms) at 4%:
Baseline:
screen shot 2015-10-13 at 4 48 34 pm

User-specified Plan (add 0.02 Itemized Deduction Benefit Surtax):
screen shot 2015-10-13 at 4 50 47 pm

General economic growth rate increase by 1%:
Baseline:
screen shot 2015-10-13 at 4 52 43 pm

User specified plan:
screen shot 2015-10-13 at 4 52 53 pm

@MattHJensen Could you take a look at the tables? I will add tests for this branch soon.

@Amy-Xu Amy-Xu changed the title [WIP]New growth rate handles New growth rate handles Oct 14, 2015
@Amy-Xu
Copy link
Member Author

Amy-Xu commented Oct 14, 2015

@MattHJensen @talumbau just added tests for this PR. Should have finished everything I have in mind. Could you review? Thanks!

@talumbau
Copy link
Member

Here are the questions that I have:

  1. Does it make sense to specify both a factor target and a factor adjustment? In my conversation with Matt, my understanding is that it does not make sense. Should we check if both are specified and raise an exception if that occurs?
  2. Is it the case that the following user_mods dictionaries should produce all the same results:
    • user_mods = {}
    • user_mods = {2015: {'_factor_target': [[0.0]]}}
    • user_mods = {2015: {'_factor_adjustment': [[0.0]]}}
      (this is relevant for certain ways a user could interact with the webapp)
  3. following the maxim of "make the common case fast", would it be OK to implement increment_year as follows:
    def increment_year(self):
        if self.growth.factor_adjustment != 0.0:
            adjustment(self, self.growth.factor_adjustment,
                       self.policy.current_year + 1)
        if np.any(self.growth._factor_target != 0.0):
            target(self, self.growth._factor_target,
                   self.policy._inflation_rates,
                   self.policy.current_year + 1)
        self.records.increment_year()
        self.policy.set_year(self.policy.current_year + 1)
        self.behavior.set_year(self.policy.current_year)

@MattHJensen
Copy link
Contributor

@Amy-Xu, quick question/comment on issue 1 from @talumbau above. Leaving replies on everything to you.

Does it make sense to specify both a factor target and a factor adjustment? In my conversation with Matt, my understanding is that it does not make sense. Should we check if both are specified and raise an exception if that occurs?

Would it make sense to do this through the validations attribute? As to raising an exception in taxcalc, we might want to do this something more general and raise an exception in taxcalc when any validation rule is violated.

cc @zrisher

@Amy-Xu
Copy link
Member Author

Amy-Xu commented Oct 14, 2015

@talumbau for the first question, yes we should check whether both are specified at the same time. But as @MattHJensen just pointed out here, I'm not quite sure where's the best place to implement this check. I can definitely do it in this PR if necessary.

Q2. Yes, if in each case that's the only thing users specified in user_mods.

Q3. Yes, that would make the common case fastest. And if I move those two condition from where they are right now to this new increment_year, those growth-rate cases wouldn't be slowed down either. I guess I can just go ahead and make the changes in this PR?

@talumbau
Copy link
Member

Q3. Yes, that would make the common case fastest. And if I move those two condition from where they are right now to this new increment_year, those growth-rate cases wouldn't be slowed down either. I guess I can just go ahead and make the changes in this PR?

Sure I think it would make sense to make the changes in this PR. On my end, I am working on getting the webapp ready for these additional inputs.

@@ -0,0 +1,24 @@
{
"_factor_adjustment":{
"long_name": "Deviation from CBO forecast of baseline economic growth (percentage point",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edit: "(percentage point" -> "(percentage point)"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually why not just "(percent)" like in _factor_target

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'm not sure 🌴 @MattHJensen?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the _factor_target allows the user to specify a GDP growth rate as a percent. The _factor_adjustment allows the user to specify a percentage point deviation from existing rates (If a existing growth rate is 10%, a 10 percent increase makes it 11%, a 10 percentage point increase makes it 20%.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. thanks

@Amy-Xu
Copy link
Member Author

Amy-Xu commented Oct 14, 2015

@talumbau @MattHJensen It doesn't seem the validation for these two parameters fits the min/max format I proposed a while ago. So I guess the easiest way to add validation would just be throwing a value error if the two parameters are non-zero at the same time. We can probably think of more general solutions later on. What do you think?

@talumbau
Copy link
Member

I would be a proponent of "ugly exception raising now, clean generalized validation behavior later" but that is just me.

@Amy-Xu
Copy link
Member Author

Amy-Xu commented Oct 14, 2015

@MattHJensen Then I guess this PR should be good now.

@MattHJensen
Copy link
Contributor

Thanks Amy. Merging.

MattHJensen added a commit that referenced this pull request Oct 14, 2015
@MattHJensen MattHJensen merged commit 2e7e7f3 into PSLmodels:master Oct 14, 2015
@Amy-Xu Amy-Xu deleted the new_growth branch November 19, 2015 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants