Coverage for HARK / rewards.py: 92%
304 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-26 06:00 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-26 06:00 +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
23def utility_fix_SG(func):
24 @functools.wraps(func)
25 def wrapper(*args, **kwargs):
26 if np.ndim(args[0]) == 0:
27 return func(*[np.array([args[0]])] + list(args[1:]), **kwargs)[0]
28 else:
29 out = func(*args, **kwargs)
30 return out
32 return wrapper
35# ==============================================================================
36# ============== Define utility functions ===============================
37# ==============================================================================
40@utility_fix
41def CRRAutility(c, rho):
42 """
43 Evaluates constant relative risk aversion (CRRA) utility of consumption c
44 given risk aversion parameter rho.
46 Parameters
47 ----------
48 c : float or array
49 Consumption value
50 rho : float
51 Risk aversion
53 Returns
54 -------
55 u : float or array
56 Utility
58 Tests
59 -----
60 Test a value which should pass:
61 >>> c, CRRA = 1.0, 2.0 # Set two values at once with Python syntax
62 >>> CRRAutility(c=c, rho=CRRA)
63 -1.0
64 """
65 if rho == 1:
66 return np.log(c)
67 return c ** (1.0 - rho) / (1.0 - rho)
70@utility_fix
71def CRRAutilityP(c, rho):
72 """
73 Evaluates constant relative risk aversion (CRRA) marginal utility of consumption
74 c given risk aversion parameter rho.
76 Parameters
77 ----------
78 c : float
79 Consumption value
80 rho : float
81 Risk aversion
83 Returns
84 -------
85 uP : float or array
86 Marginal utility
87 """
88 if rho == 1:
89 return 1 / c
90 else:
91 return c**-rho
94@utility_fix
95def CRRAutilityPP(c, rho):
96 """
97 Evaluates constant relative risk aversion (CRRA) marginal marginal utility of
98 consumption c given risk aversion parameter rho.
100 Parameters
101 ----------
102 c : float
103 Consumption value
104 rho : float
105 Risk aversion
107 Returns
108 -------
109 uPP : float
110 Marginal marginal utility
111 """
113 return -rho * c ** (-rho - 1.0)
116@utility_fix
117def CRRAutilityPPP(c, rho):
118 """
119 Evaluates constant relative risk aversion (CRRA) marginal marginal marginal
120 utility of consumption c given risk aversion parameter rho.
122 Parameters
123 ----------
124 c : float
125 Consumption value
126 rho : float
127 Risk aversion
129 Returns
130 -------
131 (unnamed) : float
132 Marginal marginal marginal utility
133 """
135 return (rho + 1.0) * rho * c ** (-rho - 2.0)
138@utility_fix
139def CRRAutilityPPPP(c, rho):
140 """
141 Evaluates constant relative risk aversion (CRRA) marginal marginal marginal
142 marginal utility of consumption c given risk aversion parameter rho.
144 Parameters
145 ----------
146 c : float
147 Consumption value
148 rho : float
149 Risk aversion
151 Returns
152 -------
153 uPPPP : float
154 Marginal marginal marginal marginal utility
155 """
156 return -(rho + 2.0) * (rho + 1.0) * rho * c ** (-rho - 3.0)
159def CRRAutility_inv(u, rho):
160 """
161 Evaluates the inverse of the CRRA utility function (with risk aversion para-
162 meter rho) at a given utility level u.
164 Parameters
165 ----------
166 u : float
167 Utility value
168 rho : float
169 Risk aversion
171 Returns
172 -------
173 (unnamed) : float
174 Consumption corresponding to given utility value
175 """
177 if rho == 1:
178 return np.exp(u)
180 return ((1.0 - rho) * u) ** (1 / (1.0 - rho))
183def CRRAutilityP_inv(uP, rho):
184 """
185 Evaluates the inverse of the CRRA marginal utility function (with risk aversion
186 parameter rho) at a given marginal utility level uP.
188 Parameters
189 ----------
190 uP : float
191 Marginal utility value
192 rho : float
193 Risk aversion
195 Returns
196 -------
197 (unnamed) : float
198 Consumption corresponding to given marginal utility value.
199 """
201 return uP ** (-1.0 / rho)
204def CRRAutility_invP(u, rho):
205 """
206 Evaluates the derivative of the inverse of the CRRA utility function (with
207 risk aversion parameter rho) at a given utility level u.
209 Parameters
210 ----------
211 u : float
212 Utility value
213 rho : float
214 Risk aversion
216 Returns
217 -------
218 (unnamed) : float
219 Marginal consumption corresponding to given utility value
220 """
222 if rho == 1:
223 return np.exp(u)
225 return ((1.0 - rho) * u) ** (rho / (1.0 - rho))
228def CRRAutilityP_invP(uP, rho):
229 """
230 Evaluates the derivative of the inverse of the CRRA marginal utility function
231 (with risk aversion parameter rho) at a given marginal utility level uP.
233 Parameters
234 ----------
235 uP : float
236 Marginal utility value
237 rho : float
238 Risk aversion
240 Returns
241 -------
242 (unnamed) : float
243 Consumption corresponding to given marginal utility value
244 """
246 return (-1.0 / rho) * uP ** (-1.0 / rho - 1.0)
249###############################################################################
251# Define legacy versions of CRRA utility functions with no decorator.
252# These are only used by the numba-fied ConsIndShockModelFast, which is not
253# compatible with the @utility_fix decorator. These functions have no docstrings
254# because they are identical to the ones above but for the lack of decorator.
257def CRRAutility_X(c, rho):
258 if rho == 1:
259 return np.log(c)
260 return c ** (1.0 - rho) / (1.0 - rho)
263def CRRAutilityP_X(c, rho):
264 if rho == 1:
265 return 1 / c
266 else:
267 return c**-rho
270def CRRAutilityPP_X(c, rho):
271 return -rho * c ** (-rho - 1.0)
274###############################################################################
277@utility_fix_SG
278def StoneGearyCRRAutility(c, rho, shifter, factor=1.0):
279 """
280 Evaluates Stone-Geary version of a constant relative risk aversion (CRRA)
281 utility of consumption c with given risk aversion parameter rho and
282 Stone-Geary intercept parameter shifter
284 Parameters
285 ----------
286 c : float
287 Consumption value
288 rho : float
289 Relative risk aversion
290 shifter : float
291 Intercept in Stone-Geary utility
292 Returns
293 -------
294 (unnamed) : float
295 Utility
297 Tests
298 -----
299 Test a value which should pass:
300 >>> c, CRRA, stone_geary = 1.0, 2.0, 0.0
301 >>> StoneGearyCRRAutility(c=c, rho=CRRA, shifter=stone_geary)
302 -1.0
303 """
305 if rho == 1:
306 return factor * np.log(shifter + c)
308 return factor * (shifter + c) ** (1.0 - rho) / (1.0 - rho)
311@utility_fix_SG
312def StoneGearyCRRAutilityP(c, rho, shifter, factor=1.0):
313 """
314 Marginal utility of Stone-Geary version of a constant relative risk aversion (CRRA)
315 utility of consumption c with a given risk aversion parameter rho and
316 Stone-Geary intercept parameter shifter
318 Parameters
319 ----------
320 c : float
321 Consumption value
322 rho : float
323 Relative risk aversion
324 shifter : float
325 Intercept in Stone-Geary utility
326 Returns
327 -------
328 (unnamed) : float
329 marginal utility
331 """
332 return factor * (shifter + c) ** (-rho)
335@utility_fix_SG
336def StoneGearyCRRAutilityPP(c, rho, shifter, factor=1.0):
337 """
338 Marginal marginal utility of Stone-Geary version of a CRRA utilty function
339 with risk aversion parameter rho and Stone-Geary intercept parameter shifter
341 Parameters
342 ----------
343 c : float
344 Consumption value
345 rho : float
346 Relative risk aversion
347 shifter : float
348 Intercept in Stone-Geary utility
349 Returns
350 -------
351 (unnamed) : float
352 marginal utility
354 """
356 return factor * (-rho) * (shifter + c) ** (-rho - 1)
359def StoneGearyCRRAutility_inv(u, rho, shifter, factor=1.0):
360 return (u * (1.0 - rho) / factor) ** (1.0 / (1.0 - rho)) - shifter
363def StoneGearyCRRAutilityP_inv(uP, rho, shifter, factor=1.0):
364 return (uP / factor) ** (-1.0 / rho) - shifter
367def StoneGearyCRRAutility_invP(u, rho, shifter, factor=1.0):
368 return (1.0 / (1.0 - rho)) * (u * (1.0 - rho) / factor) ** (1.0 / (1.0 - rho) - 1.0)
371def StoneGearyCRRAutilityP_invP(uP, rho, shifter, factor=1.0):
372 return (-1.0 / rho) * (uP / factor) ** (-1.0 / rho - 1.0)
375@utility_fix
376def CARAutility(c, alpha):
377 """
378 Evaluates constant absolute risk aversion (CARA) utility of consumption c
379 given risk aversion parameter alpha.
381 Parameters
382 ----------
383 c: float
384 Consumption value
385 alpha: float
386 Risk aversion
388 Returns
389 -------
390 (unnamed): float
391 Utility
392 """
393 return 1 - np.exp(-alpha * c) / alpha
396@utility_fix
397def CARAutilityP(c, alpha):
398 """
399 Evaluates constant absolute risk aversion (CARA) marginal utility of
400 consumption c given risk aversion parameter alpha.
402 Parameters
403 ----------
404 c: float
405 Consumption value
406 alpha: float
407 Risk aversion
409 Returns
410 -------
411 (unnamed): float
412 Marginal utility
413 """
414 return np.exp(-alpha * c)
417@utility_fix
418def CARAutilityPP(c, alpha):
419 """
420 Evaluates constant absolute risk aversion (CARA) marginal marginal utility
421 of consumption c given risk aversion parameter alpha.
423 Parameters
424 ----------
425 c: float
426 Consumption value
427 alpha: float
428 Risk aversion
430 Returns
431 -------
432 (unnamed): float
433 Marginal marginal utility
434 """
435 return -alpha * np.exp(-alpha * c)
438@utility_fix
439def CARAutilityPPP(c, alpha):
440 """
441 Evaluates constant absolute risk aversion (CARA) marginal marginal marginal
442 utility of consumption c given risk aversion parameter alpha.
444 Parameters
445 ----------
446 c: float
447 Consumption value
448 alpha: float
449 Risk aversion
451 Returns
452 -------
453 (unnamed): float
454 Marginal marginal marginal utility
455 """
456 return alpha**2.0 * np.exp(-alpha * c)
459def CARAutility_inv(u, alpha):
460 """
461 Evaluates inverse of constant absolute risk aversion (CARA) utility function
462 at utility level u given risk aversion parameter alpha.
464 Parameters
465 ----------
466 u: float
467 Utility value
468 alpha: float
469 Risk aversion
471 Returns
472 -------
473 (unnamed): float
474 Consumption value corresponding to u
475 """
476 return -1.0 / alpha * np.log(alpha * (1 - u))
479@utility_fix
480def CARAutilityP_inv(uP, alpha):
481 """
482 Evaluates the inverse of constant absolute risk aversion (CARA) marginal
483 utility function at marginal utility uP given risk aversion parameter alpha.
485 Parameters
486 ----------
487 uP: float
488 Utility value
489 alpha: float
490 Risk aversion
492 Returns
493 -------
494 (unnamed): float
495 Consumption value corresponding to uP
496 """
497 return -1.0 / alpha * np.log(uP)
500def CARAutilityP_invP(uP, alpha):
501 """
502 Evaluates the derivative of inverse of constant absolute risk aversion (CARA)
503 marginal utility function at marginal utility uP given risk aversion parameter alpha.
505 Parameters
506 ----------
507 uP: float
508 Utility value
509 alpha: float
510 Risk aversion
512 Returns
513 -------
514 (unnamed): float
515 Consumption value corresponding to uP
516 """
518 return -1.0 / (alpha * uP)
521def CARAutility_invP(u, alpha):
522 """
523 Evaluates the derivative of inverse of constant absolute risk aversion (CARA)
524 utility function at utility level u given risk aversion parameter alpha.
526 Parameters
527 ----------
528 u: float
529 Utility value
530 alpha: float
531 Risk aversion
533 Returns
534 -------
535 (unnamed): float
536 Marginal onsumption value corresponding to u
537 """
539 return 1.0 / (alpha * (1.0 - u))
542def cobb_douglas(x, zeta, factor):
543 """
544 Evaluates Cobb Douglas utility at quantities of goods consumed `x`
545 given elasticity parameters `zeta` and efficiency parameter `factor`.
547 Parameters
548 ----------
549 x : np.ndarray
550 Quantities of goods consumed. First axis must index goods.
551 zeta : np.ndarray
552 Elasticity parameters for each good. Must be consistent with `x`.
553 factor : float
554 Multiplicative efficiency parameter. (e.g. TFP in production function)
556 Returns
557 -------
558 (unnamed) : np.ndarray
559 Utility
561 """
563 # move goods axis to the end
564 goods = np.moveaxis(x, 0, -1)
566 return factor * np.sum(goods**zeta, axis=-1)
569def cobb_douglas_p(x, zeta, factor, arg=0):
570 """
571 Evaluates the marginal utility of consumption indexed by `arg` good at
572 quantities of goods consumed `x` given elasticity parameters `zeta`
573 and efficiency parameter `factor`.
575 Parameters
576 ----------
577 x : np.ndarray
578 Quantities of goods consumed. First axis must index goods.
579 zeta : np.ndarray
580 Elasticity parameters for each good. Must be consistent with `x`.
581 factor : float
582 Multiplicative efficiency parameter.
583 arg : int
584 Index of good to evaluate marginal utility.
586 Returns
587 -------
588 (unnamed) : np.ndarray
589 Utility
590 """
592 return cobb_douglas(x, zeta, factor) * zeta[arg] / x[arg]
595def cobb_douglas_pp(x, zeta, factor, args=(0, 1)):
596 """
597 Evaluates the marginal marginal utility of consumption indexed by `args`
598 at quantities of goods consumed `x` given elasticity parameters `zeta`
599 and efficiency parameter `factor`.
601 Parameters
602 ----------
603 x : np.ndarray
604 Quantities of goods consumed. First axis must index goods.
605 zeta : np.ndarray
606 Elasticity parameters for each good. Must be consistent with `x`.
607 factor : float
608 Multiplicative efficiency parameter.
609 args : tuple(int)
610 Indexes of goods to evaluate marginal utility. `args[0]` is the
611 index of the first derivative taken, and `args[1]` is the index of
612 the second derivative taken.
614 Returns
615 -------
616 (unnamed) : np.ndarray
617 Utility
618 """
620 if args[0] == args[1]:
621 coeff = zeta[args[0]] - 1
622 else:
623 coeff = zeta[args[1]]
625 return cobb_douglas_p(x, zeta, factor, args[0]) * coeff / x[args[1]]
628def cobb_douglas_pn(x, zeta, factor, args=()):
629 """
630 Evaluates the nth marginal utility of consumption indexed by `args`
631 at quantities of goods consumed `x` given elasticity parameters `zeta`
632 and efficiency parameter `factor`.
634 Parameters
635 ----------
636 x : np.ndarray
637 Quantities of goods consumed. First axis must index goods.
638 zeta : np.ndarray
639 Elasticity parameters for each good. Must be consistent with `x`.
640 factor : float
641 Multiplicative efficiency parameter.
642 args : tuple(int)
643 Indexes of goods to evaluate marginal utility. `args[0]` is the
644 index of the first derivative taken, and `args[1]` is the index of
645 the second derivative taken. This function works by recursively taking
646 derivatives, so `args` can be of any length.
648 Returns
649 -------
650 (unnamed) : np.ndarray
651 Utility
652 """
654 if isinstance(args, int):
655 args = (args,)
657 if len(args):
658 idx = args[-1] # last index
659 counts = dict(zip(*np.unique(args, return_counts=True)))
660 coeff = zeta[idx] - counts[idx] + 1
661 new_args = tuple(list(args)[:-1]) # remove last element
662 return cobb_douglas_pn(x, zeta, factor, new_args) * coeff / x[idx]
663 else:
664 return cobb_douglas(x, zeta, factor)
667def const_elast_subs(x, zeta, subs, factor, power):
668 """
669 Evaluates Constant Elasticity of Substitution utility at quantities of
670 goods consumed `x` given parameters `alpha`, 'subs', 'factor', and 'power'.
672 Parameters
673 ----------
674 x : np.ndarray
675 Quantities of goods consumed. First axis must index goods.
676 zeta : Sequence[float]
677 Share parameter for each good. Must be consistent with `x`.
678 subs : float
679 Substitution parameter.
680 factor : float
681 Factor productivity parameter. (e.g. TFP in production function)
682 power : float
683 degree of homogeneity of the utility function
685 Returns
686 -------
687 np.ndarray
688 CES utility.
689 """
691 # move goods axis to the end
692 goods = np.moveaxis(x, 0, -1)
694 return factor * np.sum(zeta * goods**subs, axis=-1) ** (power / subs)
697def const_elast_subs_p(x, zeta, subs, factor, power, arg=0):
698 """
699 Evaluates the marginal utility of consumption indexed by `arg` good at quantities
700 of goods consumed `x` given parameters `alpha`, 'subs', 'factor', and 'power'.
702 Parameters
703 ----------
704 x : np.ndarray
705 Quantities of goods consumed. First axis must index goods.
706 zeta : Sequence[float]
707 Share parameter for each good. Must be consistent with `x`.
708 subs : float
709 Substitution parameter.
710 factor : float
711 Factor productivity parameter. (e.g. TFP in production function)
712 power : float
713 degree of homogeneity of the utility function
715 Returns
716 -------
717 np.ndarray
718 CES marginal utility.
719 """
721 return (
722 const_elast_subs(x, zeta, factor * power / subs, subs, power - subs)
723 * zeta[arg]
724 * subs
725 * x[arg] ** (subs - 1)
726 )
729class UtilityFunction(MetricObject):
730 distance_criteria = ["eval_func"]
732 def __init__(self, eval_func, der_func=None, inv_func=None):
733 self.eval_func = eval_func
734 self.der_func = der_func
735 self.inv_func = inv_func
737 def __call__(self, *args, **kwargs):
738 return self.eval_func(*args, **kwargs)
740 def derivative(self, *args, **kwargs):
741 if self.der_func is None:
742 raise NotImplementedError("No derivative function available")
743 return self.der_func(*args, **kwargs)
745 def inverse(self, *args, **kwargs):
746 if self.inv_func is None:
747 raise NotImplementedError("No inverse function available")
748 return self.inv_func(*args, **kwargs)
750 def der(self, *args, **kwargs):
751 return self.derivative(*args, **kwargs)
753 def inv(self, *args, **kwargs):
754 return self.inverse(*args, **kwargs)
757def CDutility(c, d, c_share, d_bar):
758 return c**c_share * (d + d_bar) ** (1 - c_share)
761def CDutilityPc(c, d, c_share, d_bar):
762 return c_share * ((d + d_bar) / c) ** (1 - c_share)
765def CDutilityPd(c, d, c_share, d_bar):
766 return (1 - c_share) * (c / (d + d_bar)) ** c_share
769def CDutilityPc_inv(uc, d, c_share, d_bar):
770 return (d + d_bar) * (uc / c_share) ** (1 / (1 - c_share))
773def CRRACDutility(c, d, c_share, d_bar, CRRA):
774 return CDutility(c, d, c_share, d_bar) ** (1 - CRRA) / (1 - CRRA)
777def CRRACDutilityPc(c, d, c_share, d_bar, CRRA):
778 return c_share / c * CDutility(c, d, c_share, d_bar) ** (1 - CRRA)
781def CRRACDutilityPd(c, d, c_share, d_bar, CRRA):
782 return (1 - c_share) / (d + d_bar) * CDutility(c, d, c_share, d_bar) ** (1 - CRRA)
785def CRRACDutilityPc_inv(uc, d, c_share, d_bar, CRRA):
786 return (c_share / uc * (d + d_bar) ** (c_share * CRRA - c_share - CRRA + 1)) ** (
787 1 / (c_share * CRRA - c_share + 1)
788 )
791class UtilityFuncCRRA(UtilityFunction):
792 """
793 A class for representing a CRRA utility function.
795 Parameters
796 ----------
797 CRRA : float
798 The coefficient of constant relative risk aversion.
799 """
801 distance_criteria = ["CRRA"]
803 def __init__(self, CRRA):
804 self.CRRA = CRRA
806 def __call__(self, c, order=0):
807 """
808 Evaluate the utility function at a given level of consumption c.
810 Parameters
811 ----------
812 c : float or np.ndarray
813 Consumption level(s).
814 order : int, optional
815 Order of derivative. For example, `order == 1` returns the
816 first derivative of utility of consumption, and so on. By default 0.
818 Returns
819 -------
820 float or np.ndarray
821 Utility (or its derivative) evaluated at given consumption level(s).
822 """
823 if order == 0:
824 try:
825 return CRRAutility(c, self.CRRA)
826 except:
827 return CRRAutility_X(c, self.CRRA)
828 else: # order >= 1
829 return self.derivative(c, order)
831 def derivative(self, c, order=1):
832 """
833 The derivative of the utility function at a given level of consumption c.
835 Parameters
836 ----------
837 c : float or np.ndarray
838 Consumption level(s).
839 order : int, optional
840 Order of derivative. For example, `order == 1` returns the
841 first derivative of utility of consumption, and so on. By default 1.
843 Returns
844 -------
845 float or np.ndarray
846 Derivative of CRRA utility evaluated at given consumption level(s).
848 Raises
849 ------
850 ValueError
851 Derivative of order higher than 4 is not supported.
852 """
853 if order == 1:
854 try:
855 return CRRAutilityP(c, self.CRRA)
856 except:
857 return CRRAutilityP_X(c, self.CRRA)
858 elif order == 2:
859 try:
860 return CRRAutilityPP(c, self.CRRA)
861 except:
862 return CRRAutilityPP_X(c, self.CRRA)
863 elif order == 3:
864 return CRRAutilityPPP(c, self.CRRA)
865 elif order == 4:
866 return CRRAutilityPPPP(c, self.CRRA)
867 else:
868 raise ValueError(f"Derivative of order {order} not supported")
870 def inverse(self, u, order=(0, 0)):
871 """
872 The inverse of the utility function at a given level of utility u.
874 Parameters
875 ----------
876 u : float or np.ndarray
877 Utility level(s).
878 order : tuple, optional
879 Order of derivatives. For example, `order == (1,1)` represents
880 the first derivative of utility, inverted, and then differentiated
881 once. For a simple mnemonic, order refers to the number of `P`s in
882 the function `CRRAutility[#1]_inv[#2]`. By default (0, 0),
883 which is just the inverse of utility.
885 Returns
886 -------
887 float or np.ndarray
888 Inverse of CRRA utility evaluated at given utility level(s).
890 Raises
891 ------
892 ValueError
893 Higher order derivatives are not supported.
894 """
895 if order == (0, 0):
896 return CRRAutility_inv(u, self.CRRA)
897 elif order == (1, 0):
898 return CRRAutilityP_inv(u, self.CRRA)
899 elif order == (0, 1):
900 return CRRAutility_invP(u, self.CRRA)
901 elif order == (1, 1):
902 return CRRAutilityP_invP(u, self.CRRA)
903 else:
904 raise ValueError(f"Inverse of order {order} not supported")
906 def derinv(self, u, order=(1, 0)):
907 """
908 Short alias for inverse with default order = (1,0). See `self.inverse`.
909 """
910 return self.inverse(u, order)
913class UtilityFuncCARA(UtilityFunction):
914 """
915 A class for representing a CARA utility function.
917 Parameters
918 ----------
919 CARA : float
920 The coefficient of constant absolute risk aversion.
921 """
923 distance_criteria = ["CARA"]
925 def __init__(self, CARA):
926 self.CARA = CARA
928 def __call__(self, c, order=0):
929 """
930 Evaluate the utility function at a given level of consumption c.
932 Parameters
933 ----------
934 c : float or np.ndarray
935 Consumption level(s).
936 order : int, optional
937 Order of derivative. For example, `order == 1` returns the
938 first derivative of utility of consumption, and so on. By default 0.
940 Returns
941 -------
942 float or np.ndarray
943 Utility (or its derivative) evaluated at given consumption level(s).
944 """
945 if order == 0:
946 return CARAutility(c, self.CARA)
947 else: # order >= 1
948 return self.derivative(c, order)
950 def derivative(self, c, order=1):
951 """
952 The derivative of the utility function at a given level of consumption c.
954 Parameters
955 ----------
956 c : float or np.ndarray
957 Consumption level(s).
958 order : int, optional
959 Order of derivative. For example, `order == 1` returns the
960 first derivative of utility of consumption, and so on. By default 1.
962 Returns
963 -------
964 float or np.ndarray
965 Derivative of CRRA utility evaluated at given consumption level(s).
967 Raises
968 ------
969 ValueError
970 Derivative of order higher than 4 is not supported.
971 """
972 if order == 1:
973 return CARAutilityP(c, self.CARA)
974 elif order == 2:
975 return CARAutilityPP(c, self.CARA)
976 elif order == 3:
977 return CARAutilityPPP(c, self.CARA)
978 else:
979 raise ValueError(f"Derivative of order {order} not supported")
981 def inverse(self, u, order=(0, 0)):
982 """
983 The inverse of the utility function at a given level of utility u.
985 Parameters
986 ----------
987 u : float or np.ndarray
988 Utility level(s).
989 order : tuple, optional
990 Order of derivatives. For example, `order == (1,1)` represents
991 the first derivative of utility, inverted, and then differentiated
992 once. For a simple mnemonic, order refers to the number of `P`s in
993 the function `CRRAutility[#1]_inv[#2]`. By default (0, 0),
994 which is just the inverse of utility.
996 Returns
997 -------
998 float or np.ndarray
999 Inverse of CRRA utility evaluated at given utility level(s).
1001 Raises
1002 ------
1003 ValueError
1004 Higher order derivatives are not supported.
1005 """
1006 if order == (0, 0):
1007 return CARAutility_inv(u, self.CARA)
1008 elif order == (1, 0):
1009 return CARAutilityP_inv(u, self.CARA)
1010 elif order == (0, 1):
1011 return CARAutility_invP(u, self.CARA)
1012 elif order == (1, 1):
1013 return CARAutilityP_invP(u, self.CARA)
1014 else:
1015 raise ValueError(f"Inverse of order {order} not supported")
1017 def derinv(self, u, order=(1, 0)):
1018 """
1019 Short alias for inverse with default order = (1,0). See `self.inverse`.
1020 """
1021 return self.inverse(u, order)
1024class UtilityFuncStoneGeary(UtilityFunction):
1025 distance_criteria = ["CRRA", "factor", "shifter"]
1027 def __init__(self, CRRA, factor=1.0, shifter=0.0):
1028 self.CRRA = CRRA
1029 self.factor = factor
1030 self.shifter = shifter
1032 def __call__(self, c, order=0):
1033 if order == 0:
1034 return StoneGearyCRRAutility(c, self.CRRA, self.shifter, self.factor)
1035 else: # order >= 1
1036 return self.derivative(c, order)
1038 def derivative(self, c, order=1):
1039 if order == 1:
1040 return StoneGearyCRRAutilityP(c, self.CRRA, self.shifter, self.factor)
1041 elif order == 2:
1042 return StoneGearyCRRAutilityPP(c, self.CRRA, self.shifter, self.factor)
1043 else:
1044 raise ValueError(f"Derivative of order {order} not supported")
1046 def inverse(self, u, order=(0, 0)):
1047 if order == (0, 0):
1048 return StoneGearyCRRAutility_inv(u, self.CRRA, self.shifter, self.factor)
1049 elif order == (1, 0):
1050 return StoneGearyCRRAutilityP_inv(u, self.CRRA, self.shifter, self.factor)
1051 elif order == (0, 1):
1052 return StoneGearyCRRAutility_invP(u, self.CRRA, self.shifter, self.factor)
1053 elif order == (1, 1):
1054 return StoneGearyCRRAutilityP_invP(u, self.CRRA, self.shifter, self.factor)
1055 else:
1056 raise ValueError(f"Inverse of order {order} not supported")
1059class UtilityFuncCobbDouglas(UtilityFunction):
1060 """
1061 A class for representing a Cobb-Douglas utility function.
1063 TODO: Add inverse methods.
1065 Parameters
1066 ----------
1067 c_share : float
1068 Share parameter for consumption. Must be between 0 and 1.
1069 d_bar : float
1070 Intercept parameter for durable consumption. Must be non-negative.
1071 """
1073 distance_criteria = ["c_share", "d_bar"]
1075 def __init__(self, c_share, d_bar=0):
1076 self.c_share = c_share
1077 self.d_bar = d_bar
1079 assert 0 <= c_share <= 1, "Share parameter must be between 0 and 1."
1081 def __call__(self, c, d):
1082 """
1083 Evaluate the utility function at a given level of consumption c.
1084 """
1085 return CDutility(c, d, self.c_share, self.d_bar)
1087 def derivative(self, c, d, axis=0):
1088 if axis == 0:
1089 return CDutilityPc(c, d, self.c_share, self.d_bar)
1090 elif axis == 1:
1091 return CDutilityPd(c, d, self.c_share, self.d_bar)
1092 else:
1093 raise ValueError(f"Axis must be 0 or 1, not {axis}")
1095 def inverse(self, uc, d):
1096 return CDutilityPc_inv(uc, d, self.c_share, self.d_bar)
1099class UtilityFuncCobbDouglasCRRA(UtilityFuncCobbDouglas):
1100 """
1101 A class for representing a Cobb-Douglas aggregated CRRA utility function.
1103 TODO: Add derivative and inverse methods.
1105 Parameters
1106 ----------
1107 c_share : float
1108 Share parameter for consumption. Must be between 0 and 1.
1109 d_bar : float
1110 Intercept parameter for durable consumption. Must be non-negative.
1111 CRRA: float
1112 Coefficient of relative risk aversion.
1113 """
1115 distance_criteria = ["c_share", "d_bar", "CRRA"]
1117 def __init__(self, c_share, CRRA, d_bar=0):
1118 super().__init__(c_share, d_bar)
1119 self.CRRA = CRRA
1121 def __call__(self, c, d):
1122 return CRRACDutility(c, d, self.c_share, self.d_bar, self.CRRA)
1124 def derivative(self, c, d, axis=0):
1125 if axis == 0:
1126 return CRRACDutilityPc(c, d, self.c_share, self.d_bar, self.CRRA)
1127 elif axis == 1:
1128 return CRRACDutilityPd(c, d, self.c_share, self.d_bar, self.CRRA)
1129 else:
1130 raise ValueError(f"Axis must be 0 or 1, not {axis}")
1132 def inverse(self, uc, d):
1133 return CRRACDutilityPc_inv(uc, d, self.c_share, self.d_bar, self.CRRA)
1136class UtilityFuncConstElastSubs(UtilityFunction):
1137 """
1138 A class for representing a constant elasticity of substitution utility function.
1140 TODO: Add derivative and inverse methods.
1142 Parameters
1143 ----------
1144 shares : Sequence[float]
1145 Share parameter for each good. Must be consistent with `x`.
1146 subs : float
1147 Substitution parameter.
1148 factor : float
1149 Factor productivity parameter. (e.g. TFP in production function)
1150 homogeneity : float
1151 degree of homogeneity of the utility function
1152 """
1154 distance_criteria = ["shares", "subs", "factor", "homogeneity"]
1156 def __init__(self, shares, subs, homogeneity=1.0, factor=1.0):
1157 assert subs != 0.0, "Consider using a Cobb-Douglas utility function instead."
1158 assert subs != 1.0, "Linear utility is not implemented."
1160 self.shares = np.asarray(shares)
1161 self.subs = subs
1162 self.homogeneity = homogeneity
1163 self.factor = factor
1165 self.CES = 1 / (1 - subs)
1166 self.dim = self.shares.size # number of goods
1168 def __call__(self, x):
1169 return const_elast_subs(
1170 x, self.shares, self.subs, self.factor, self.homogeneity
1171 )
1173 def derivative(self, x, arg=0):
1174 return const_elast_subs_p(
1175 x, self.shares, self.subs, self.factor, self.homogeneity, arg
1176 )