Coverage for HARK / rewards.py: 92%
295 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-07 05:16 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-07 05:16 +0000
1import numpy as np
2from HARK.metric import MetricObject
3import functools
6def utility_fix(func):
7 @functools.wraps(func)
8 def wrapper(*args, **kwargs):
9 if np.ndim(args[0]) == 0:
10 if args[0] < 0.0:
11 return np.nan
12 else:
13 return func(*[np.array([args[0]])] + list(args[1:]), **kwargs)[0]
14 else:
15 out = func(*args, **kwargs)
16 neg = args[0] < 0.0
17 out[neg] = np.nan
18 return out
20 return wrapper
23# ==============================================================================
24# ============== Define utility functions ===============================
25# ==============================================================================
28@utility_fix
29def CRRAutility(c, rho):
30 """
31 Evaluates constant relative risk aversion (CRRA) utility of consumption c
32 given risk aversion parameter rho.
34 Parameters
35 ----------
36 c : float or array
37 Consumption value
38 rho : float
39 Risk aversion
41 Returns
42 -------
43 u : float or array
44 Utility
46 Tests
47 -----
48 Test a value which should pass:
49 >>> c, CRRA = 1.0, 2.0 # Set two values at once with Python syntax
50 >>> CRRAutility(c=c, rho=CRRA)
51 -1.0
52 """
53 if rho == 1:
54 return np.log(c)
55 return c ** (1.0 - rho) / (1.0 - rho)
58@utility_fix
59def CRRAutilityP(c, rho):
60 """
61 Evaluates constant relative risk aversion (CRRA) marginal utility of consumption
62 c given risk aversion parameter rho.
64 Parameters
65 ----------
66 c : float
67 Consumption value
68 rho : float
69 Risk aversion
71 Returns
72 -------
73 uP : float or array
74 Marginal utility
75 """
76 if rho == 1:
77 return 1 / c
78 else:
79 return c**-rho
82@utility_fix
83def CRRAutilityPP(c, rho):
84 """
85 Evaluates constant relative risk aversion (CRRA) marginal marginal utility of
86 consumption c given risk aversion parameter rho.
88 Parameters
89 ----------
90 c : float
91 Consumption value
92 rho : float
93 Risk aversion
95 Returns
96 -------
97 uPP : float
98 Marginal marginal utility
99 """
101 return -rho * c ** (-rho - 1.0)
104@utility_fix
105def CRRAutilityPPP(c, rho):
106 """
107 Evaluates constant relative risk aversion (CRRA) marginal marginal marginal
108 utility of consumption c given risk aversion parameter rho.
110 Parameters
111 ----------
112 c : float
113 Consumption value
114 rho : float
115 Risk aversion
117 Returns
118 -------
119 (unnamed) : float
120 Marginal marginal marginal utility
121 """
123 return (rho + 1.0) * rho * c ** (-rho - 2.0)
126@utility_fix
127def CRRAutilityPPPP(c, rho):
128 """
129 Evaluates constant relative risk aversion (CRRA) marginal marginal marginal
130 marginal utility of consumption c given risk aversion parameter rho.
132 Parameters
133 ----------
134 c : float
135 Consumption value
136 rho : float
137 Risk aversion
139 Returns
140 -------
141 uPPPP : float
142 Marginal marginal marginal marginal utility
143 """
144 return -(rho + 2.0) * (rho + 1.0) * rho * c ** (-rho - 3.0)
147def CRRAutility_inv(u, rho):
148 """
149 Evaluates the inverse of the CRRA utility function (with risk aversion para-
150 meter rho) at a given utility level u.
152 Parameters
153 ----------
154 u : float
155 Utility value
156 rho : float
157 Risk aversion
159 Returns
160 -------
161 (unnamed) : float
162 Consumption corresponding to given utility value
163 """
165 if rho == 1:
166 return np.exp(u)
168 return ((1.0 - rho) * u) ** (1 / (1.0 - rho))
171def CRRAutilityP_inv(uP, rho):
172 """
173 Evaluates the inverse of the CRRA marginal utility function (with risk aversion
174 parameter rho) at a given marginal utility level uP.
176 Parameters
177 ----------
178 uP : float
179 Marginal utility value
180 rho : float
181 Risk aversion
183 Returns
184 -------
185 (unnamed) : float
186 Consumption corresponding to given marginal utility value.
187 """
189 return uP ** (-1.0 / rho)
192def CRRAutility_invP(u, rho):
193 """
194 Evaluates the derivative of the inverse of the CRRA utility function (with
195 risk aversion parameter rho) at a given utility level u.
197 Parameters
198 ----------
199 u : float
200 Utility value
201 rho : float
202 Risk aversion
204 Returns
205 -------
206 (unnamed) : float
207 Marginal consumption corresponding to given utility value
208 """
210 if rho == 1:
211 return np.exp(u)
213 return ((1.0 - rho) * u) ** (rho / (1.0 - rho))
216def CRRAutilityP_invP(uP, rho):
217 """
218 Evaluates the derivative of the inverse of the CRRA marginal utility function
219 (with risk aversion parameter rho) at a given marginal utility level uP.
221 Parameters
222 ----------
223 uP : float
224 Marginal utility value
225 rho : float
226 Risk aversion
228 Returns
229 -------
230 (unnamed) : float
231 Consumption corresponding to given marginal utility value
232 """
234 return (-1.0 / rho) * uP ** (-1.0 / rho - 1.0)
237###############################################################################
239# Define legacy versions of CRRA utility functions with no decorator.
240# These are only used by the numba-fied ConsIndShockModelFast, which is not
241# compatible with the @utility_fix decorator. These functions have no docstrings
242# because they are identical to the ones above but for the lack of decorator.
245def CRRAutility_X(c, rho):
246 if rho == 1:
247 return np.log(c)
248 return c ** (1.0 - rho) / (1.0 - rho)
251def CRRAutilityP_X(c, rho):
252 if rho == 1:
253 return 1 / c
254 else:
255 return c**-rho
258def CRRAutilityPP_X(c, rho):
259 return -rho * c ** (-rho - 1.0)
262###############################################################################
265@utility_fix
266def StoneGearyCRRAutility(c, rho, shifter, factor=1.0):
267 """
268 Evaluates Stone-Geary version of a constant relative risk aversion (CRRA)
269 utility of consumption c with given risk aversion parameter rho and
270 Stone-Geary intercept parameter shifter
272 Parameters
273 ----------
274 c : float
275 Consumption value
276 rho : float
277 Relative risk aversion
278 shifter : float
279 Intercept in Stone-Geary utility
280 Returns
281 -------
282 (unnamed) : float
283 Utility
285 Tests
286 -----
287 Test a value which should pass:
288 >>> c, CRRA, stone_geary = 1.0, 2.0, 0.0
289 >>> StoneGearyCRRAutility(c=c, rho=CRRA, shifter=stone_geary)
290 -1.0
291 """
293 if rho == 1:
294 return factor * np.log(shifter + c)
296 return factor * (shifter + c) ** (1.0 - rho) / (1.0 - rho)
299@utility_fix
300def StoneGearyCRRAutilityP(c, rho, shifter, factor=1.0):
301 """
302 Marginal utility of Stone-Geary version of a constant relative risk aversion (CRRA)
303 utility of consumption c with a given risk aversion parameter rho and
304 Stone-Geary intercept parameter shifter
306 Parameters
307 ----------
308 c : float
309 Consumption value
310 rho : float
311 Relative risk aversion
312 shifter : float
313 Intercept in Stone-Geary utility
314 Returns
315 -------
316 (unnamed) : float
317 marginal utility
319 """
321 return factor * (shifter + c) ** (-rho)
324@utility_fix
325def StoneGearyCRRAutilityPP(c, rho, shifter, factor=1.0):
326 """
327 Marginal marginal utility of Stone-Geary version of a CRRA utilty function
328 with risk aversion parameter rho and Stone-Geary intercept parameter shifter
330 Parameters
331 ----------
332 c : float
333 Consumption value
334 rho : float
335 Relative risk aversion
336 shifter : float
337 Intercept in Stone-Geary utility
338 Returns
339 -------
340 (unnamed) : float
341 marginal utility
343 """
345 return factor * (-rho) * (shifter + c) ** (-rho - 1)
348def StoneGearyCRRAutility_inv(u, rho, shifter, factor=1.0):
349 return (u * (1.0 - rho) / factor) ** (1.0 / (1.0 - rho)) - shifter
352def StoneGearyCRRAutilityP_inv(uP, rho, shifter, factor=1.0):
353 return (uP / factor) ** (-1.0 / rho) - shifter
356def StoneGearyCRRAutility_invP(u, rho, shifter, factor=1.0):
357 return (1.0 / (1.0 - rho)) * (u * (1.0 - rho) / factor) ** (1.0 / (1.0 - rho) - 1.0)
360def StoneGearyCRRAutilityP_invP(uP, rho, shifter, factor=1.0):
361 return (-1.0 / rho) * (uP / factor) ** (-1.0 / rho - 1.0)
364@utility_fix
365def CARAutility(c, alpha):
366 """
367 Evaluates constant absolute risk aversion (CARA) utility of consumption c
368 given risk aversion parameter alpha.
370 Parameters
371 ----------
372 c: float
373 Consumption value
374 alpha: float
375 Risk aversion
377 Returns
378 -------
379 (unnamed): float
380 Utility
381 """
382 return 1 - np.exp(-alpha * c) / alpha
385@utility_fix
386def CARAutilityP(c, alpha):
387 """
388 Evaluates constant absolute risk aversion (CARA) marginal utility of
389 consumption c given risk aversion parameter alpha.
391 Parameters
392 ----------
393 c: float
394 Consumption value
395 alpha: float
396 Risk aversion
398 Returns
399 -------
400 (unnamed): float
401 Marginal utility
402 """
403 return np.exp(-alpha * c)
406@utility_fix
407def CARAutilityPP(c, alpha):
408 """
409 Evaluates constant absolute risk aversion (CARA) marginal marginal utility
410 of consumption c given risk aversion parameter alpha.
412 Parameters
413 ----------
414 c: float
415 Consumption value
416 alpha: float
417 Risk aversion
419 Returns
420 -------
421 (unnamed): float
422 Marginal marginal utility
423 """
424 return -alpha * np.exp(-alpha * c)
427@utility_fix
428def CARAutilityPPP(c, alpha):
429 """
430 Evaluates constant absolute risk aversion (CARA) marginal marginal marginal
431 utility of consumption c given risk aversion parameter alpha.
433 Parameters
434 ----------
435 c: float
436 Consumption value
437 alpha: float
438 Risk aversion
440 Returns
441 -------
442 (unnamed): float
443 Marginal marginal marginal utility
444 """
445 return alpha**2.0 * np.exp(-alpha * c)
448def CARAutility_inv(u, alpha):
449 """
450 Evaluates inverse of constant absolute risk aversion (CARA) utility function
451 at utility level u given risk aversion parameter alpha.
453 Parameters
454 ----------
455 u: float
456 Utility value
457 alpha: float
458 Risk aversion
460 Returns
461 -------
462 (unnamed): float
463 Consumption value corresponding to u
464 """
465 return -1.0 / alpha * np.log(alpha * (1 - u))
468@utility_fix
469def CARAutilityP_inv(uP, alpha):
470 """
471 Evaluates the inverse of constant absolute risk aversion (CARA) marginal
472 utility function at marginal utility uP given risk aversion parameter alpha.
474 Parameters
475 ----------
476 uP: float
477 Utility value
478 alpha: float
479 Risk aversion
481 Returns
482 -------
483 (unnamed): float
484 Consumption value corresponding to uP
485 """
486 return -1.0 / alpha * np.log(uP)
489def CARAutilityP_invP(uP, alpha):
490 """
491 Evaluates the derivative of inverse of constant absolute risk aversion (CARA)
492 marginal utility function at marginal utility uP given risk aversion parameter alpha.
494 Parameters
495 ----------
496 uP: float
497 Utility value
498 alpha: float
499 Risk aversion
501 Returns
502 -------
503 (unnamed): float
504 Consumption value corresponding to uP
505 """
507 return -1.0 / (alpha * uP)
510def CARAutility_invP(u, alpha):
511 """
512 Evaluates the derivative of inverse of constant absolute risk aversion (CARA)
513 utility function at utility level u given risk aversion parameter alpha.
515 Parameters
516 ----------
517 u: float
518 Utility value
519 alpha: float
520 Risk aversion
522 Returns
523 -------
524 (unnamed): float
525 Marginal onsumption value corresponding to u
526 """
528 return 1.0 / (alpha * (1.0 - u))
531def cobb_douglas(x, zeta, factor):
532 """
533 Evaluates Cobb Douglas utility at quantities of goods consumed `x`
534 given elasticity parameters `zeta` and efficiency parameter `factor`.
536 Parameters
537 ----------
538 x : np.ndarray
539 Quantities of goods consumed. First axis must index goods.
540 zeta : np.ndarray
541 Elasticity parameters for each good. Must be consistent with `x`.
542 factor : float
543 Multiplicative efficiency parameter. (e.g. TFP in production function)
545 Returns
546 -------
547 (unnamed) : np.ndarray
548 Utility
550 """
552 # move goods axis to the end
553 goods = np.moveaxis(x, 0, -1)
555 return factor * np.sum(goods**zeta, axis=-1)
558def cobb_douglas_p(x, zeta, factor, arg=0):
559 """
560 Evaluates the marginal utility of consumption indexed by `arg` good at
561 quantities of goods consumed `x` given elasticity parameters `zeta`
562 and efficiency parameter `factor`.
564 Parameters
565 ----------
566 x : np.ndarray
567 Quantities of goods consumed. First axis must index goods.
568 zeta : np.ndarray
569 Elasticity parameters for each good. Must be consistent with `x`.
570 factor : float
571 Multiplicative efficiency parameter.
572 arg : int
573 Index of good to evaluate marginal utility.
575 Returns
576 -------
577 (unnamed) : np.ndarray
578 Utility
579 """
581 return cobb_douglas(x, zeta, factor) * zeta[arg] / x[arg]
584def cobb_douglas_pp(x, zeta, factor, args=(0, 1)):
585 """
586 Evaluates the marginal marginal utility of consumption indexed by `args`
587 at quantities of goods consumed `x` given elasticity parameters `zeta`
588 and efficiency parameter `factor`.
590 Parameters
591 ----------
592 x : np.ndarray
593 Quantities of goods consumed. First axis must index goods.
594 zeta : np.ndarray
595 Elasticity parameters for each good. Must be consistent with `x`.
596 factor : float
597 Multiplicative efficiency parameter.
598 args : tuple(int)
599 Indexes of goods to evaluate marginal utility. `args[0]` is the
600 index of the first derivative taken, and `args[1]` is the index of
601 the second derivative taken.
603 Returns
604 -------
605 (unnamed) : np.ndarray
606 Utility
607 """
609 if args[0] == args[1]:
610 coeff = zeta[args[0]] - 1
611 else:
612 coeff = zeta[args[1]]
614 return cobb_douglas_p(x, zeta, factor, args[0]) * coeff / x[args[1]]
617def cobb_douglas_pn(x, zeta, factor, args=()):
618 """
619 Evaluates the nth marginal utility of consumption indexed by `args`
620 at quantities of goods consumed `x` given elasticity parameters `zeta`
621 and efficiency parameter `factor`.
623 Parameters
624 ----------
625 x : np.ndarray
626 Quantities of goods consumed. First axis must index goods.
627 zeta : np.ndarray
628 Elasticity parameters for each good. Must be consistent with `x`.
629 factor : float
630 Multiplicative efficiency parameter.
631 args : tuple(int)
632 Indexes of goods to evaluate marginal utility. `args[0]` is the
633 index of the first derivative taken, and `args[1]` is the index of
634 the second derivative taken. This function works by recursively taking
635 derivatives, so `args` can be of any length.
637 Returns
638 -------
639 (unnamed) : np.ndarray
640 Utility
641 """
643 if isinstance(args, int):
644 args = (args,)
646 if len(args):
647 idx = args[-1] # last index
648 counts = dict(zip(*np.unique(args, return_counts=True)))
649 coeff = zeta[idx] - counts[idx] + 1
650 new_args = tuple(list(args)[:-1]) # remove last element
651 return cobb_douglas_pn(x, zeta, factor, new_args) * coeff / x[idx]
652 else:
653 return cobb_douglas(x, zeta, factor)
656def const_elast_subs(x, zeta, subs, factor, power):
657 """
658 Evaluates Constant Elasticity of Substitution utility at quantities of
659 goods consumed `x` given parameters `alpha`, 'subs', 'factor', and 'power'.
661 Parameters
662 ----------
663 x : np.ndarray
664 Quantities of goods consumed. First axis must index goods.
665 zeta : Sequence[float]
666 Share parameter for each good. Must be consistent with `x`.
667 subs : float
668 Substitution parameter.
669 factor : float
670 Factor productivity parameter. (e.g. TFP in production function)
671 power : float
672 degree of homogeneity of the utility function
674 Returns
675 -------
676 np.ndarray
677 CES utility.
678 """
680 # move goods axis to the end
681 goods = np.moveaxis(x, 0, -1)
683 return factor * np.sum(zeta * goods**subs, axis=-1) ** (power / subs)
686def const_elast_subs_p(x, zeta, subs, factor, power, arg=0):
687 """
688 Evaluates the marginal utility of consumption indexed by `arg` good at quantities
689 of goods consumed `x` given parameters `alpha`, 'subs', 'factor', and 'power'.
691 Parameters
692 ----------
693 x : np.ndarray
694 Quantities of goods consumed. First axis must index goods.
695 zeta : Sequence[float]
696 Share parameter for each good. Must be consistent with `x`.
697 subs : float
698 Substitution parameter.
699 factor : float
700 Factor productivity parameter. (e.g. TFP in production function)
701 power : float
702 degree of homogeneity of the utility function
704 Returns
705 -------
706 np.ndarray
707 CES marginal utility.
708 """
710 return (
711 const_elast_subs(x, zeta, factor * power / subs, subs, power - subs)
712 * zeta[arg]
713 * subs
714 * x[arg] ** (subs - 1)
715 )
718class UtilityFunction(MetricObject):
719 distance_criteria = ["eval_func"]
721 def __init__(self, eval_func, der_func=None, inv_func=None):
722 self.eval_func = eval_func
723 self.der_func = der_func
724 self.inv_func = inv_func
726 def __call__(self, *args, **kwargs):
727 return self.eval_func(*args, **kwargs)
729 def derivative(self, *args, **kwargs):
730 if self.der_func is None:
731 raise NotImplementedError("No derivative function available")
732 return self.der_func(*args, **kwargs)
734 def inverse(self, *args, **kwargs):
735 if self.inv_func is None:
736 raise NotImplementedError("No inverse function available")
737 return self.inv_func(*args, **kwargs)
739 def der(self, *args, **kwargs):
740 return self.derivative(*args, **kwargs)
742 def inv(self, *args, **kwargs):
743 return self.inverse(*args, **kwargs)
746def CDutility(c, d, c_share, d_bar):
747 return c**c_share * (d + d_bar) ** (1 - c_share)
750def CDutilityPc(c, d, c_share, d_bar):
751 return c_share * ((d + d_bar) / c) ** (1 - c_share)
754def CDutilityPd(c, d, c_share, d_bar):
755 return (1 - c_share) * (c / (d + d_bar)) ** c_share
758def CDutilityPc_inv(uc, d, c_share, d_bar):
759 return (d + d_bar) * (uc / c_share) ** (1 / (1 - c_share))
762def CRRACDutility(c, d, c_share, d_bar, CRRA):
763 return CDutility(c, d, c_share, d_bar) ** (1 - CRRA) / (1 - CRRA)
766def CRRACDutilityPc(c, d, c_share, d_bar, CRRA):
767 return c_share / c * CDutility(c, d, c_share, d_bar) ** (1 - CRRA)
770def CRRACDutilityPd(c, d, c_share, d_bar, CRRA):
771 return (1 - c_share) / (d + d_bar) * CDutility(c, d, c_share, d_bar) ** (1 - CRRA)
774def CRRACDutilityPc_inv(uc, d, c_share, d_bar, CRRA):
775 return (c_share / uc * (d + d_bar) ** (c_share * CRRA - c_share - CRRA + 1)) ** (
776 1 / (c_share * CRRA - c_share + 1)
777 )
780class UtilityFuncCRRA(UtilityFunction):
781 """
782 A class for representing a CRRA utility function.
784 Parameters
785 ----------
786 CRRA : float
787 The coefficient of constant relative risk aversion.
788 """
790 distance_criteria = ["CRRA"]
792 def __init__(self, CRRA):
793 self.CRRA = CRRA
795 def __call__(self, c, order=0):
796 """
797 Evaluate the utility function at a given level of consumption c.
799 Parameters
800 ----------
801 c : float or np.ndarray
802 Consumption level(s).
803 order : int, optional
804 Order of derivative. For example, `order == 1` returns the
805 first derivative of utility of consumption, and so on. By default 0.
807 Returns
808 -------
809 float or np.ndarray
810 Utility (or its derivative) evaluated at given consumption level(s).
811 """
812 if order == 0:
813 try:
814 return CRRAutility(c, self.CRRA)
815 except:
816 return CRRAutility_X(c, self.CRRA)
817 else: # order >= 1
818 return self.derivative(c, order)
820 def derivative(self, c, order=1):
821 """
822 The derivative of the utility function at a given level of consumption c.
824 Parameters
825 ----------
826 c : float or np.ndarray
827 Consumption level(s).
828 order : int, optional
829 Order of derivative. For example, `order == 1` returns the
830 first derivative of utility of consumption, and so on. By default 1.
832 Returns
833 -------
834 float or np.ndarray
835 Derivative of CRRA utility evaluated at given consumption level(s).
837 Raises
838 ------
839 ValueError
840 Derivative of order higher than 4 is not supported.
841 """
842 if order == 1:
843 try:
844 return CRRAutilityP(c, self.CRRA)
845 except:
846 return CRRAutilityP_X(c, self.CRRA)
847 elif order == 2:
848 try:
849 return CRRAutilityPP(c, self.CRRA)
850 except:
851 return CRRAutilityPP_X(c, self.CRRA)
852 elif order == 3:
853 return CRRAutilityPPP(c, self.CRRA)
854 elif order == 4:
855 return CRRAutilityPPPP(c, self.CRRA)
856 else:
857 raise ValueError(f"Derivative of order {order} not supported")
859 def inverse(self, u, order=(0, 0)):
860 """
861 The inverse of the utility function at a given level of utility u.
863 Parameters
864 ----------
865 u : float or np.ndarray
866 Utility level(s).
867 order : tuple, optional
868 Order of derivatives. For example, `order == (1,1)` represents
869 the first derivative of utility, inverted, and then differentiated
870 once. For a simple mnemonic, order refers to the number of `P`s in
871 the function `CRRAutility[#1]_inv[#2]`. By default (0, 0),
872 which is just the inverse of utility.
874 Returns
875 -------
876 float or np.ndarray
877 Inverse of CRRA utility evaluated at given utility level(s).
879 Raises
880 ------
881 ValueError
882 Higher order derivatives are not supported.
883 """
884 if order == (0, 0):
885 return CRRAutility_inv(u, self.CRRA)
886 elif order == (1, 0):
887 return CRRAutilityP_inv(u, self.CRRA)
888 elif order == (0, 1):
889 return CRRAutility_invP(u, self.CRRA)
890 elif order == (1, 1):
891 return CRRAutilityP_invP(u, self.CRRA)
892 else:
893 raise ValueError(f"Inverse of order {order} not supported")
895 def derinv(self, u, order=(1, 0)):
896 """
897 Short alias for inverse with default order = (1,0). See `self.inverse`.
898 """
899 return self.inverse(u, order)
902class UtilityFuncCARA(UtilityFunction):
903 """
904 A class for representing a CARA utility function.
906 Parameters
907 ----------
908 CARA : float
909 The coefficient of constant absolute risk aversion.
910 """
912 distance_criteria = ["CARA"]
914 def __init__(self, CARA):
915 self.CARA = CARA
917 def __call__(self, c, order=0):
918 """
919 Evaluate the utility function at a given level of consumption c.
921 Parameters
922 ----------
923 c : float or np.ndarray
924 Consumption level(s).
925 order : int, optional
926 Order of derivative. For example, `order == 1` returns the
927 first derivative of utility of consumption, and so on. By default 0.
929 Returns
930 -------
931 float or np.ndarray
932 Utility (or its derivative) evaluated at given consumption level(s).
933 """
934 if order == 0:
935 return CARAutility(c, self.CARA)
936 else: # order >= 1
937 return self.derivative(c, order)
939 def derivative(self, c, order=1):
940 """
941 The derivative of the utility function at a given level of consumption c.
943 Parameters
944 ----------
945 c : float or np.ndarray
946 Consumption level(s).
947 order : int, optional
948 Order of derivative. For example, `order == 1` returns the
949 first derivative of utility of consumption, and so on. By default 1.
951 Returns
952 -------
953 float or np.ndarray
954 Derivative of CRRA utility evaluated at given consumption level(s).
956 Raises
957 ------
958 ValueError
959 Derivative of order higher than 4 is not supported.
960 """
961 if order == 1:
962 return CARAutilityP(c, self.CARA)
963 elif order == 2:
964 return CARAutilityPP(c, self.CARA)
965 elif order == 3:
966 return CARAutilityPPP(c, self.CARA)
967 else:
968 raise ValueError(f"Derivative of order {order} not supported")
970 def inverse(self, u, order=(0, 0)):
971 """
972 The inverse of the utility function at a given level of utility u.
974 Parameters
975 ----------
976 u : float or np.ndarray
977 Utility level(s).
978 order : tuple, optional
979 Order of derivatives. For example, `order == (1,1)` represents
980 the first derivative of utility, inverted, and then differentiated
981 once. For a simple mnemonic, order refers to the number of `P`s in
982 the function `CRRAutility[#1]_inv[#2]`. By default (0, 0),
983 which is just the inverse of utility.
985 Returns
986 -------
987 float or np.ndarray
988 Inverse of CRRA utility evaluated at given utility level(s).
990 Raises
991 ------
992 ValueError
993 Higher order derivatives are not supported.
994 """
995 if order == (0, 0):
996 return CARAutility_inv(u, self.CARA)
997 elif order == (1, 0):
998 return CARAutilityP_inv(u, self.CARA)
999 elif order == (0, 1):
1000 return CARAutility_invP(u, self.CARA)
1001 elif order == (1, 1):
1002 return CARAutilityP_invP(u, self.CARA)
1003 else:
1004 raise ValueError(f"Inverse of order {order} not supported")
1006 def derinv(self, u, order=(1, 0)):
1007 """
1008 Short alias for inverse with default order = (1,0). See `self.inverse`.
1009 """
1010 return self.inverse(u, order)
1013class UtilityFuncStoneGeary(UtilityFuncCRRA):
1014 def __init__(self, CRRA, factor=1.0, shifter=0.0):
1015 self.CRRA = CRRA
1016 self.factor = factor
1017 self.shifter = shifter
1019 def __call__(self, c, order=0):
1020 if order == 0:
1021 return StoneGearyCRRAutility(c, self.CRRA, self.shifter, self.factor)
1022 else: # order >= 1
1023 return self.derivative(c, order)
1025 def derivative(self, c, order=1):
1026 if order == 1:
1027 return StoneGearyCRRAutilityP(c, self.CRRA, self.shifter, self.factor)
1028 elif order == 2:
1029 return StoneGearyCRRAutilityPP(c, self.CRRA, self.shifter, self.factor)
1030 else:
1031 raise ValueError(f"Derivative of order {order} not supported")
1033 def inverse(self, u, order=(0, 0)):
1034 if order == (0, 0):
1035 return StoneGearyCRRAutility_inv(u, self.CRRA, self.shifter, self.factor)
1036 elif order == (1, 0):
1037 return StoneGearyCRRAutilityP_inv(u, self.CRRA, self.shifter, self.factor)
1038 elif order == (0, 1):
1039 return StoneGearyCRRAutility_invP(u, self.CRRA, self.shifter, self.factor)
1040 elif order == (1, 1):
1041 return StoneGearyCRRAutilityP_invP(u, self.CRRA, self.shifter, self.factor)
1042 else:
1043 raise ValueError(f"Inverse of order {order} not supported")
1046class UtilityFuncCobbDouglas(UtilityFunction):
1047 """
1048 A class for representing a Cobb-Douglas utility function.
1050 TODO: Add inverse methods.
1052 Parameters
1053 ----------
1054 c_share : float
1055 Share parameter for consumption. Must be between 0 and 1.
1056 d_bar : float
1057 Intercept parameter for durable consumption. Must be non-negative.
1058 """
1060 distance_criteria = ["c_share", "d_bar"]
1062 def __init__(self, c_share, d_bar=0):
1063 self.c_share = c_share
1064 self.d_bar = d_bar
1066 assert 0 <= c_share <= 1, "Share parameter must be between 0 and 1."
1068 def __call__(self, c, d):
1069 """
1070 Evaluate the utility function at a given level of consumption c.
1071 """
1072 return CDutility(c, d, self.c_share, self.d_bar)
1074 def derivative(self, c, d, axis=0):
1075 if axis == 0:
1076 return CDutilityPc(c, d, self.c_share, self.d_bar)
1077 elif axis == 1:
1078 return CDutilityPd(c, d, self.c_share, self.d_bar)
1079 else:
1080 raise ValueError(f"Axis must be 0 or 1, not {axis}")
1082 def inverse(self, uc, d):
1083 return CDutilityPc_inv(uc, d, self.c_share, self.d_bar)
1086class UtilityFuncCobbDouglasCRRA(UtilityFuncCobbDouglas):
1087 """
1088 A class for representing a Cobb-Douglas aggregated CRRA utility function.
1090 TODO: Add derivative and inverse methods.
1092 Parameters
1093 ----------
1094 c_share : float
1095 Share parameter for consumption. Must be between 0 and 1.
1096 d_bar : float
1097 Intercept parameter for durable consumption. Must be non-negative.
1098 CRRA: float
1099 Coefficient of relative risk aversion.
1100 """
1102 distance_criteria = ["c_share", "d_bar", "CRRA"]
1104 def __init__(self, c_share, CRRA, d_bar=0):
1105 super().__init__(c_share, d_bar)
1106 self.CRRA = CRRA
1108 def __call__(self, c, d):
1109 return CRRACDutility(c, d, self.c_share, self.d_bar, self.CRRA)
1111 def derivative(self, c, d, axis=0):
1112 if axis == 0:
1113 return CRRACDutilityPc(c, d, self.c_share, self.d_bar, self.CRRA)
1114 elif axis == 1:
1115 return CRRACDutilityPd(c, d, self.c_share, self.d_bar, self.CRRA)
1116 else:
1117 raise ValueError(f"Axis must be 0 or 1, not {axis}")
1119 def inverse(self, uc, d):
1120 return CRRACDutilityPc_inv(uc, d, self.c_share, self.d_bar, self.CRRA)
1123class UtilityFuncConstElastSubs(UtilityFunction):
1124 """
1125 A class for representing a constant elasticity of substitution utility function.
1127 TODO: Add derivative and inverse methods.
1129 Parameters
1130 ----------
1131 shares : Sequence[float]
1132 Share parameter for each good. Must be consistent with `x`.
1133 subs : float
1134 Substitution parameter.
1135 factor : float
1136 Factor productivity parameter. (e.g. TFP in production function)
1137 homogeneity : float
1138 degree of homogeneity of the utility function
1139 """
1141 distance_criteria = ["shares", "subs", "factor", "homogeneity"]
1143 def __init__(self, shares, subs, homogeneity=1.0, factor=1.0):
1144 assert subs != 0.0, "Consider using a Cobb-Douglas utility function instead."
1145 assert subs != 1.0, "Linear utility is not implemented."
1147 self.shares = np.asarray(shares)
1148 self.subs = subs
1149 self.homogeneity = homogeneity
1150 self.factor = factor
1152 self.CES = 1 / (1 - subs)
1153 self.dim = self.shares.size # number of goods
1155 def __call__(self, x):
1156 return const_elast_subs(
1157 x, self.shares, self.subs, self.factor, self.homogeneity
1158 )
1160 def derivative(self, x, arg=0):
1161 return const_elast_subs_p(
1162 x, self.shares, self.subs, self.factor, self.homogeneity, arg
1163 )