Coverage for HARK/rewards.py: 74%
266 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-02 05:14 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-02 05:14 +0000
1import numpy as np
2from HARK.metric import MetricObject
4# ==============================================================================
5# ============== Define utility functions ===============================
6# ==============================================================================
9def CRRAutility(c, rho):
10 """
11 Evaluates constant relative risk aversion (CRRA) utility of consumption c
12 given risk aversion parameter rho.
14 Parameters
15 ----------
16 c : float
17 Consumption value
18 rho : float
19 Risk aversion
21 Returns
22 -------
23 (unnamed) : float
24 Utility
26 Tests
27 -----
28 Test a value which should pass:
29 >>> c, CRRA = 1.0, 2.0 # Set two values at once with Python syntax
30 >>> CRRAutility(c=c, rho=CRRA)
31 -1.0
32 """
34 if np.isscalar(c):
35 c = np.asarray(c)
36 if rho == 1:
37 return np.log(c)
39 return c ** (1.0 - rho) / (1.0 - rho)
42def CRRAutilityP(c, rho):
43 """
44 Evaluates constant relative risk aversion (CRRA) marginal utility of consumption
45 c given risk aversion parameter rho.
47 Parameters
48 ----------
49 c : float
50 Consumption value
51 rho : float
52 Risk aversion
54 Returns
55 -------
56 (unnamed) : float
57 Marginal utility
58 """
60 if np.isscalar(c):
61 c = np.asarray(c)
62 if rho == 1:
63 return 1 / c
65 return c**-rho
68def CRRAutilityPP(c, rho):
69 """
70 Evaluates constant relative risk aversion (CRRA) marginal marginal utility of
71 consumption c given risk aversion parameter rho.
73 Parameters
74 ----------
75 c : float
76 Consumption value
77 rho : float
78 Risk aversion
80 Returns
81 -------
82 (unnamed) : float
83 Marginal marginal utility
84 """
86 if np.isscalar(c):
87 c = np.asarray(c)
88 return -rho * c ** (-rho - 1.0)
91def CRRAutilityPPP(c, rho):
92 """
93 Evaluates constant relative risk aversion (CRRA) marginal marginal marginal
94 utility of consumption c given risk aversion parameter rho.
96 Parameters
97 ----------
98 c : float
99 Consumption value
100 rho : float
101 Risk aversion
103 Returns
104 -------
105 (unnamed) : float
106 Marginal marginal marginal utility
107 """
109 if np.isscalar(c):
110 c = np.asarray(c)
111 return (rho + 1.0) * rho * c ** (-rho - 2.0)
114def CRRAutilityPPPP(c, rho):
115 """
116 Evaluates constant relative risk aversion (CRRA) marginal marginal marginal
117 marginal utility of consumption c given risk aversion parameter rho.
119 Parameters
120 ----------
121 c : float
122 Consumption value
123 rho : float
124 Risk aversion
126 Returns
127 -------
128 (unnamed) : float
129 Marginal marginal marginal marginal utility
130 """
132 if np.isscalar(c):
133 c = np.asarray(c)
134 return -(rho + 2.0) * (rho + 1.0) * rho * c ** (-rho - 3.0)
137def CRRAutility_inv(u, rho):
138 """
139 Evaluates the inverse of the CRRA utility function (with risk aversion para-
140 meter rho) at a given utility level u.
142 Parameters
143 ----------
144 u : float
145 Utility value
146 rho : float
147 Risk aversion
149 Returns
150 -------
151 (unnamed) : float
152 Consumption corresponding to given utility value
153 """
155 if np.isscalar(u):
156 u = np.asarray(u)
157 if rho == 1:
158 return np.exp(u)
160 return ((1.0 - rho) * u) ** (1 / (1.0 - rho))
163def CRRAutilityP_inv(uP, rho):
164 """
165 Evaluates the inverse of the CRRA marginal utility function (with risk aversion
166 parameter rho) at a given marginal utility level uP.
168 Parameters
169 ----------
170 uP : float
171 Marginal utility value
172 rho : float
173 Risk aversion
175 Returns
176 -------
177 (unnamed) : float
178 Consumption corresponding to given marginal utility value.
179 """
181 if np.isscalar(uP):
182 uP = np.asarray(uP)
183 return uP ** (-1.0 / rho)
186def CRRAutility_invP(u, rho):
187 """
188 Evaluates the derivative of the inverse of the CRRA utility function (with
189 risk aversion parameter rho) at a given utility level u.
191 Parameters
192 ----------
193 u : float
194 Utility value
195 rho : float
196 Risk aversion
198 Returns
199 -------
200 (unnamed) : float
201 Marginal consumption corresponding to given utility value
202 """
204 if np.isscalar(u):
205 u = np.asarray(u)
206 if rho == 1:
207 return np.exp(u)
209 return ((1.0 - rho) * u) ** (rho / (1.0 - rho))
212def CRRAutilityP_invP(uP, rho):
213 """
214 Evaluates the derivative of the inverse of the CRRA marginal utility function
215 (with risk aversion parameter rho) at a given marginal utility level uP.
217 Parameters
218 ----------
219 uP : float
220 Marginal utility value
221 rho : float
222 Risk aversion
224 Returns
225 -------
226 (unnamed) : float
227 Consumption corresponding to given marginal utility value
228 """
230 if np.isscalar(uP):
231 uP = np.asarray(uP)
232 return (-1.0 / rho) * uP ** (-1.0 / rho - 1.0)
235def StoneGearyCRRAutility(c, rho, shifter, factor=1.0):
236 """
237 Evaluates Stone-Geary version of a constant relative risk aversion (CRRA)
238 utility of consumption c with given risk aversion parameter rho and
239 Stone-Geary intercept parameter shifter
241 Parameters
242 ----------
243 c : float
244 Consumption value
245 rho : float
246 Relative risk aversion
247 shifter : float
248 Intercept in Stone-Geary utility
249 Returns
250 -------
251 (unnamed) : float
252 Utility
254 Tests
255 -----
256 Test a value which should pass:
257 >>> c, CRRA, stone_geary = 1.0, 2.0, 0.0
258 >>> StoneGearyCRRAutility(c=c, rho=CRRA, shifter=stone_geary)
259 -1.0
260 """
262 if np.isscalar(c):
263 c = np.asarray(c)
264 if rho == 1:
265 return factor * np.log(shifter + c)
267 return factor * (shifter + c) ** (1.0 - rho) / (1.0 - rho)
270def StoneGearyCRRAutilityP(c, rho, shifter, factor=1.0):
271 """
272 Marginal utility of Stone-Geary version of a constant relative risk aversion (CRRA)
273 utility of consumption c with a given risk aversion parameter rho and
274 Stone-Geary intercept parameter shifter
276 Parameters
277 ----------
278 c : float
279 Consumption value
280 rho : float
281 Relative risk aversion
282 shifter : float
283 Intercept in Stone-Geary utility
284 Returns
285 -------
286 (unnamed) : float
287 marginal utility
289 """
291 if np.isscalar(c):
292 c = np.asarray(c)
293 return factor * (shifter + c) ** (-rho)
296def StoneGearyCRRAutilityPP(c, rho, shifter, factor=1.0):
297 """
298 Marginal marginal utility of Stone-Geary version of a CRRA utilty function
299 with risk aversion parameter rho and Stone-Geary intercept parameter shifter
301 Parameters
302 ----------
303 c : float
304 Consumption value
305 rho : float
306 Relative risk aversion
307 shifter : float
308 Intercept in Stone-Geary utility
309 Returns
310 -------
311 (unnamed) : float
312 marginal utility
314 """
316 if np.isscalar(c):
317 c = np.asarray(c)
318 return factor * (-rho) * (shifter + c) ** (-rho - 1)
321def StoneGearyCRRAutility_inv(u, rho, shifter, factor=1.0):
322 if np.isscalar(u):
323 u = np.asarray(u)
325 return (u * (1.0 - rho) / factor) ** (1.0 / (1.0 - rho)) - shifter
328def StoneGearyCRRAutilityP_inv(uP, rho, shifter, factor=1.0):
329 if np.isscalar(uP):
330 uP = np.asarray(uP)
332 return (uP / factor) ** (-1.0 / rho) - shifter
335def StoneGearyCRRAutility_invP(u, rho, shifter, factor=1.0):
336 if np.isscalar(u):
337 u = np.asarray(u)
339 return (1.0 / (1.0 - rho)) * (u * (1.0 - rho) / factor) ** (1.0 / (1.0 - rho) - 1.0)
342def StoneGearyCRRAutilityP_invP(uP, rho, shifter, factor=1.0):
343 if np.isscalar(uP):
344 uP = np.asarray(uP)
346 return (-1.0 / rho) * (uP / factor) ** (-1.0 / rho - 1.0)
349def CARAutility(c, alpha):
350 """
351 Evaluates constant absolute risk aversion (CARA) utility of consumption c
352 given risk aversion parameter alpha.
354 Parameters
355 ----------
356 c: float
357 Consumption value
358 alpha: float
359 Risk aversion
361 Returns
362 -------
363 (unnamed): float
364 Utility
365 """
367 if np.isscalar(c):
368 c = np.asarray(c)
369 return 1 - np.exp(-alpha * c) / alpha
372def CARAutilityP(c, alpha):
373 """
374 Evaluates constant absolute risk aversion (CARA) marginal utility of
375 consumption c given risk aversion parameter alpha.
377 Parameters
378 ----------
379 c: float
380 Consumption value
381 alpha: float
382 Risk aversion
384 Returns
385 -------
386 (unnamed): float
387 Marginal utility
388 """
390 if np.isscalar(c):
391 c = np.asarray(c)
392 return np.exp(-alpha * c)
395def CARAutilityPP(c, alpha):
396 """
397 Evaluates constant absolute risk aversion (CARA) marginal marginal utility
398 of consumption c given risk aversion parameter alpha.
400 Parameters
401 ----------
402 c: float
403 Consumption value
404 alpha: float
405 Risk aversion
407 Returns
408 -------
409 (unnamed): float
410 Marginal marginal utility
411 """
413 if np.isscalar(c):
414 c = np.asarray(c)
415 return -alpha * np.exp(-alpha * c)
418def CARAutilityPPP(c, alpha):
419 """
420 Evaluates constant absolute risk aversion (CARA) marginal marginal marginal
421 utility 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 marginal utility
434 """
436 if np.isscalar(c):
437 c = np.asarray(c)
438 return alpha**2.0 * np.exp(-alpha * c)
441def CARAutility_inv(u, alpha):
442 """
443 Evaluates inverse of constant absolute risk aversion (CARA) utility function
444 at utility level u given risk aversion parameter alpha.
446 Parameters
447 ----------
448 u: float
449 Utility value
450 alpha: float
451 Risk aversion
453 Returns
454 -------
455 (unnamed): float
456 Consumption value corresponding to u
457 """
459 if np.isscalar(u):
460 u = np.asarray(u)
461 return -1.0 / alpha * np.log(alpha * (1 - u))
464def CARAutilityP_inv(u, alpha):
465 """
466 Evaluates the inverse of constant absolute risk aversion (CARA) marginal
467 utility function at marginal utility uP given risk aversion parameter alpha.
469 Parameters
470 ----------
471 u: float
472 Utility value
473 alpha: float
474 Risk aversion
476 Returns
477 -------
478 (unnamed): float
479 Consumption value corresponding to uP
480 """
482 if np.isscalar(u):
483 u = np.asarray(u)
484 return -1.0 / alpha * np.log(u)
487def CARAutility_invP(u, alpha):
488 """
489 Evaluates the derivative of inverse of constant absolute risk aversion (CARA)
490 utility function at utility level u given risk aversion parameter alpha.
492 Parameters
493 ----------
494 u: float
495 Utility value
496 alpha: float
497 Risk aversion
499 Returns
500 -------
501 (unnamed): float
502 Marginal onsumption value corresponding to u
503 """
505 if np.isscalar(u):
506 u = np.asarray(u)
507 return 1.0 / (alpha * (1.0 - u))
510def cobb_douglas(x, zeta, factor):
511 """
512 Evaluates Cobb Douglas utility at quantities of goods consumed `x`
513 given elasticity parameters `zeta` and efficiency parameter `factor`.
515 Parameters
516 ----------
517 x : np.ndarray
518 Quantities of goods consumed. First axis must index goods.
519 zeta : np.ndarray
520 Elasticity parameters for each good. Must be consistent with `x`.
521 factor : float
522 Multiplicative efficiency parameter. (e.g. TFP in production function)
524 Returns
525 -------
526 (unnamed) : np.ndarray
527 Utility
529 """
531 # move goods axis to the end
532 goods = np.moveaxis(x, 0, -1)
534 return factor * np.sum(goods**zeta, axis=-1)
537def cobb_douglas_p(x, zeta, factor, arg=0):
538 """
539 Evaluates the marginal utility of consumption indexed by `arg` good at
540 quantities of goods consumed `x` given elasticity parameters `zeta`
541 and efficiency parameter `factor`.
543 Parameters
544 ----------
545 x : np.ndarray
546 Quantities of goods consumed. First axis must index goods.
547 zeta : np.ndarray
548 Elasticity parameters for each good. Must be consistent with `x`.
549 factor : float
550 Multiplicative efficiency parameter.
551 arg : int
552 Index of good to evaluate marginal utility.
554 Returns
555 -------
556 (unnamed) : np.ndarray
557 Utility
558 """
560 return cobb_douglas(x, zeta, factor) * zeta[arg] / x[arg]
563def cobb_douglas_pp(x, zeta, factor, args=(0, 1)):
564 """
565 Evaluates the marginal marginal utility of consumption indexed by `args`
566 at quantities of goods consumed `x` given elasticity parameters `zeta`
567 and efficiency parameter `factor`.
569 Parameters
570 ----------
571 x : np.ndarray
572 Quantities of goods consumed. First axis must index goods.
573 zeta : np.ndarray
574 Elasticity parameters for each good. Must be consistent with `x`.
575 factor : float
576 Multiplicative efficiency parameter.
577 args : tuple(int)
578 Indexes of goods to evaluate marginal utility. `args[0]` is the
579 index of the first derivative taken, and `args[1]` is the index of
580 the second derivative taken.
582 Returns
583 -------
584 (unnamed) : np.ndarray
585 Utility
586 """
588 if args[0] == args[1]:
589 coeff = zeta[args[0]] - 1
590 else:
591 coeff = zeta[args[1]]
593 return cobb_douglas_p(x, zeta, factor, args[0]) * coeff / x[args[1]]
596def cobb_douglas_pn(x, zeta, factor, args=()):
597 """
598 Evaluates the nth marginal utility of consumption indexed by `args`
599 at quantities of goods consumed `x` given elasticity parameters `zeta`
600 and efficiency parameter `factor`.
602 Parameters
603 ----------
604 x : np.ndarray
605 Quantities of goods consumed. First axis must index goods.
606 zeta : np.ndarray
607 Elasticity parameters for each good. Must be consistent with `x`.
608 factor : float
609 Multiplicative efficiency parameter.
610 args : tuple(int)
611 Indexes of goods to evaluate marginal utility. `args[0]` is the
612 index of the first derivative taken, and `args[1]` is the index of
613 the second derivative taken. This function works by recursively taking
614 derivatives, so `args` can be of any length.
616 Returns
617 -------
618 (unnamed) : np.ndarray
619 Utility
620 """
622 if isinstance(args, int):
623 args = (args,)
625 if len(args):
626 idx = args[-1] # last index
627 counts = dict(zip(*np.unique(args, return_counts=True)))
628 coeff = zeta[idx] - counts[idx] + 1
629 new_args = tuple(list(args)[:-1]) # remove last element
630 return cobb_douglas_pn(x, zeta, factor, new_args) * coeff / x[idx]
631 else:
632 return cobb_douglas(x, zeta, factor)
635def const_elast_subs(x, zeta, subs, factor, power):
636 """
637 Evaluates Constant Elasticity of Substitution utility at quantities of
638 goods consumed `x` given parameters `alpha`, 'subs', 'factor', and 'power'.
640 Parameters
641 ----------
642 x : np.ndarray
643 Quantities of goods consumed. First axis must index goods.
644 zeta : Sequence[float]
645 Share parameter for each good. Must be consistent with `x`.
646 subs : float
647 Substitution parameter.
648 factor : float
649 Factor productivity parameter. (e.g. TFP in production function)
650 power : float
651 degree of homogeneity of the utility function
653 Returns
654 -------
655 np.ndarray
656 CES utility.
657 """
659 # move goods axis to the end
660 goods = np.moveaxis(x, 0, -1)
662 return factor * np.sum(zeta * goods**subs, axis=-1) ** (power / subs)
665def const_elast_subs_p(x, zeta, subs, factor, power, arg=0):
666 """
667 Evaluates the marginal utility of consumption indexed by `arg` good at quantities
668 of goods consumed `x` given parameters `alpha`, 'subs', 'factor', and 'power'.
670 Parameters
671 ----------
672 x : np.ndarray
673 Quantities of goods consumed. First axis must index goods.
674 zeta : Sequence[float]
675 Share parameter for each good. Must be consistent with `x`.
676 subs : float
677 Substitution parameter.
678 factor : float
679 Factor productivity parameter. (e.g. TFP in production function)
680 power : float
681 degree of homogeneity of the utility function
683 Returns
684 -------
685 np.ndarray
686 CES marginal utility.
687 """
689 return (
690 const_elast_subs(x, zeta, factor * power / subs, subs, power - subs)
691 * zeta[arg]
692 * subs
693 * x[arg] ** (subs - 1)
694 )
697class UtilityFunction(MetricObject):
698 distance_criteria = ["eval_func"]
700 def __init__(self, eval_func, der_func=None, inv_func=None):
701 self.eval_func = eval_func
702 self.der_func = der_func
703 self.inv_func = inv_func
705 def __call__(self, *args, **kwargs):
706 return self.eval_func(*args, **kwargs)
708 def derivative(self, *args, **kwargs):
709 if not hasattr(self, "der_func") or self.der_func is None:
710 raise NotImplementedError("No derivative function available")
711 return self.der_func(*args, **kwargs)
713 def inverse(self, *args, **kwargs):
714 if not hasattr(self, "inv_func") or self.inv_func is None:
715 raise NotImplementedError("No inverse function available")
716 return self.inv_func(*args, **kwargs)
718 def der(self, *args, **kwargs):
719 return self.derivative(*args, **kwargs)
721 def inv(self, *args, **kwargs):
722 return self.inverse(*args, **kwargs)
725def CDutility(c, d, c_share, d_bar):
726 return c**c_share * (d + d_bar) ** (1 - c_share)
729def CDutilityPc(c, d, c_share, d_bar):
730 return c_share * ((d + d_bar) / c) ** (1 - c_share)
733def CDutilityPd(c, d, c_share, d_bar):
734 return (1 - c_share) * (c / (d + d_bar)) ** c_share
737def CDutilityPc_inv(uc, d, c_share, d_bar):
738 return (d + d_bar) * (uc / c_share) ** (1 / (1 - c_share))
741def CRRACDutility(c, d, c_share, d_bar, CRRA):
742 return CDutility(c, d, c_share, d_bar) ** (1 - CRRA) / (1 - CRRA)
745def CRRACDutilityPc(c, d, c_share, d_bar, CRRA):
746 return c_share / c * CDutility(c, d, c_share, d_bar) ** (1 - CRRA)
749def CRRACDutilityPd(c, d, c_share, d_bar, CRRA):
750 return (1 - c_share) / (d + d_bar) * CDutility(c, d, c_share, d_bar) ** (1 - CRRA)
753def CRRACDutilityPc_inv(uc, d, c_share, d_bar, CRRA):
754 return (c_share / uc * (d + d_bar) ** (c_share * CRRA - c_share - CRRA + 1)) ** (
755 1 / (c_share * CRRA - c_share + 1)
756 )
759class UtilityFuncCRRA(UtilityFunction):
760 """
761 A class for representing a CRRA utility function.
763 Parameters
764 ----------
765 CRRA : float
766 The coefficient of constant relative risk aversion.
767 """
769 distance_criteria = ["CRRA"]
771 def __init__(self, CRRA):
772 self.CRRA = CRRA
774 def __call__(self, c, order=0):
775 """
776 Evaluate the utility function at a given level of consumption c.
778 Parameters
779 ----------
780 c : float or np.ndarray
781 Consumption level(s).
782 order : int, optional
783 Order of derivative. For example, `order == 1` returns the
784 first derivative of utility of consumption, and so on. By default 0.
786 Returns
787 -------
788 float or np.ndarray
789 Utility (or its derivative) evaluated at given consumption level(s).
790 """
791 if order == 0:
792 return CRRAutility(c, self.CRRA)
793 else: # order >= 1
794 return self.derivative(c, order)
796 def derivative(self, c, order=1):
797 """
798 The derivative of the utility function at a given level of consumption c.
800 Parameters
801 ----------
802 c : float or np.ndarray
803 Consumption level(s).
804 order : int, optional
805 Order of derivative. For example, `order == 1` returns the
806 first derivative of utility of consumption, and so on. By default 1.
808 Returns
809 -------
810 float or np.ndarray
811 Derivative of CRRA utility evaluated at given consumption level(s).
813 Raises
814 ------
815 ValueError
816 Derivative of order higher than 4 is not supported.
817 """
818 if order == 1:
819 return CRRAutilityP(c, self.CRRA)
820 elif order == 2:
821 return CRRAutilityPP(c, self.CRRA)
822 elif order == 3:
823 return CRRAutilityPPP(c, self.CRRA)
824 elif order == 4:
825 return CRRAutilityPPPP(c, self.CRRA)
826 else:
827 raise ValueError(f"Derivative of order {order} not supported")
829 def inverse(self, u, order=(0, 0)):
830 """
831 The inverse of the utility function at a given level of utility u.
833 Parameters
834 ----------
835 u : float or np.ndarray
836 Utility level(s).
837 order : tuple, optional
838 Order of derivatives. For example, `order == (1,1)` represents
839 the first derivative of utility, inverted, and then differentiated
840 once. For a simple mnemonic, order refers to the number of `P`s in
841 the function `CRRAutility[#1]_inv[#2]`. By default (0, 0),
842 which is just the inverse of utility.
844 Returns
845 -------
846 float or np.ndarray
847 Inverse of CRRA utility evaluated at given utility level(s).
849 Raises
850 ------
851 ValueError
852 Higher order derivatives are not supported.
853 """
854 if order == (0, 0):
855 return CRRAutility_inv(u, self.CRRA)
856 elif order == (1, 0):
857 return CRRAutilityP_inv(u, self.CRRA)
858 elif order == (0, 1):
859 return CRRAutility_invP(u, self.CRRA)
860 elif order == (1, 1):
861 return CRRAutilityP_invP(u, self.CRRA)
862 else:
863 raise ValueError(f"Inverse of order {order} not supported")
865 def derinv(self, u, order=(1, 0)):
866 """
867 Short alias for inverse with default order = (1,0). See `self.inverse`.
868 """
869 return self.inverse(u, order)
872class UtilityFuncStoneGeary(UtilityFuncCRRA):
873 def __init__(self, CRRA, factor=1.0, shifter=0.0):
874 self.CRRA = CRRA
875 self.factor = factor
876 self.shifter = shifter
878 def __call__(self, c, order=0):
879 if order == 0:
880 return StoneGearyCRRAutility(c, self.CRRA, self.shifter, self.factor)
881 else: # order >= 1
882 return self.derivative(c, order)
884 def derivative(self, c, order=1):
885 if order == 1:
886 return StoneGearyCRRAutilityP(c, self.CRRA, self.shifter, self.factor)
887 elif order == 2:
888 return StoneGearyCRRAutilityPP(c, self.CRRA, self.shifter, self.factor)
889 else:
890 raise ValueError(f"Derivative of order {order} not supported")
892 def inverse(self, u, order=(0, 0)):
893 if order == (0, 0):
894 return StoneGearyCRRAutility_inv(u, self.CRRA, self.shifter, self.factor)
895 elif order == (1, 0):
896 return StoneGearyCRRAutilityP_inv(u, self.CRRA, self.shifter, self.factor)
897 elif order == (0, 1):
898 return StoneGearyCRRAutility_invP(u, self.CRRA, self.shifter, self.factor)
899 elif order == (1, 1):
900 return StoneGearyCRRAutilityP_invP(u, self.CRRA, self.shifter, self.factor)
901 else:
902 raise ValueError(f"Inverse of order {order} not supported")
905class UtilityFuncCobbDouglas(UtilityFunction):
906 """
907 A class for representing a Cobb-Douglas utility function.
909 TODO: Add inverse methods.
911 Parameters
912 ----------
913 c_share : float
914 Share parameter for consumption. Must be between 0 and 1.
915 d_bar : float
916 Intercept parameter for durable consumption. Must be non-negative.
917 """
919 distance_criteria = ["c_share", "d_bar"]
921 def __init__(self, c_share, d_bar=0):
922 self.c_share = c_share
923 self.d_bar = d_bar
925 assert 0 <= c_share <= 1, "Share parameter must be between 0 and 1."
927 def __call__(self, c, d):
928 """
929 Evaluate the utility function at a given level of consumption c.
930 """
931 return CDutility(c, d, self.c_share, self.d_bar)
933 def derivative(self, c, d, axis=0):
934 if axis == 0:
935 return CDutilityPc(c, d, self.c_share, self.d_bar)
936 elif axis == 1:
937 return CDutilityPd(c, d, self.c_share, self.d_bar)
938 else:
939 raise ValueError(f"Axis must be 0 or 1, not {axis}")
941 def inverse(self, uc, d):
942 return CDutilityPc_inv(uc, d, self.c_share, self.d_bar)
945class UtilityFuncCobbDouglasCRRA(UtilityFuncCobbDouglas):
946 """
947 A class for representing a Cobb-Douglas aggregated CRRA utility function.
949 TODO: Add derivative and inverse methods.
951 Parameters
952 ----------
953 c_share : float
954 Share parameter for consumption. Must be between 0 and 1.
955 d_bar : float
956 Intercept parameter for durable consumption. Must be non-negative.
957 CRRA: float
958 Coefficient of relative risk aversion.
959 """
961 distance_criteria = ["c_share", "d_bar", "CRRA"]
963 def __init__(self, c_share, CRRA, d_bar=0):
964 super().__init__(c_share, d_bar)
965 self.CRRA = CRRA
967 def __call__(self, c, d):
968 return CRRACDutility(c, d, self.c_share, self.d_bar, self.CRRA)
970 def derivative(self, c, d, axis=0):
971 if axis == 0:
972 return CRRACDutilityPc(c, d, self.c_share, self.d_bar, self.CRRA)
973 elif axis == 1:
974 return CRRACDutilityPd(c, d, self.c_share, self.d_bar, self.CRRA)
975 else:
976 raise ValueError(f"Axis must be 0 or 1, not {axis}")
978 def inverse(self, uc, d):
979 return CRRACDutilityPc_inv(uc, d, self.c_share, self.d_bar, self.CRRA)
982class UtilityFuncConstElastSubs(UtilityFunction):
983 """
984 A class for representing a constant elasticity of substitution utility function.
986 TODO: Add derivative and inverse methods.
988 Parameters
989 ----------
990 shares : Sequence[float]
991 Share parameter for each good. Must be consistent with `x`.
992 subs : float
993 Substitution parameter.
994 factor : float
995 Factor productivity parameter. (e.g. TFP in production function)
996 homogeneity : float
997 degree of homogeneity of the utility function
998 """
1000 distance_criteria = ["shares", "subs", "factor", "homogeneity"]
1002 def __init__(self, shares, subs, homogeneity=1.0, factor=1.0):
1003 assert subs != 0.0, "Consider using a Cobb-Douglas utility function instead."
1004 assert subs != 1.0, "Linear utility is not implemented."
1006 self.shares = np.asarray(shares)
1007 self.subs = subs
1008 self.homogeneity = homogeneity
1009 self.factor = factor
1011 self.CES = 1 / (1 - subs)
1012 self.dim = self.shares.size # number of goods
1014 def __call__(self, x):
1015 return const_elast_subs(
1016 x, self.shares, self.subs, self.factor, self.homogeneity
1017 )
1019 def derivative(self, x, arg=0):
1020 return const_elast_subs_p(
1021 x, self.shares, self.subs, self.factor, self.homogeneity, arg
1022 )