text: from ctypes import util
  import numpy as np
  import scipy as sp
  from scipy import optimize
  
  class InsuranceClass():
      """
      This class solves the insurance problem
      """
      def __init__(self): #called when created
  
          #defining baseline parameters
          self.y = 1          #Agent's assets
          self.p = 0.2        #Probability of incurring a loss
          self.vartheta =-2   #The degree of relative risk aversion in the utility function
          self.x = 0.6        #Monetary loss incurres with probability p
          self.q = np.nan     #Insurance coverage in case of loss 
  
      #utility function
      def utility(self, z):
          """ Defining the CRRA utility function for the agent.
          Args:
              self (list): list of baseline parameter values.
              z (float): the asset level entering the function.
          
          Returns:
              u (float): utility value for agent.
          """  
          #u = z**(1 + self.vartheta) / (1 + self.vartheta)
          u = np.float_power(z, 1 + self.vartheta) / (1 + self.vartheta)
          return u
      
      #Insurance company premium dependent on p,q
      def premium(self, q):
          """ Defining the insurance premium as proportional to probability of loss and size of coverage.
          Args:
              self (list): list of baseline parameter values.
              q: Insurance coverage to be optimized.
          
          Returns:
              pi (float): Insurance premium.
          """  
          pi = self.p*q
      
          return pi
  
      #Expected utility function 
      def exp_utility(self, q):
          """ Returns expected utility to be maximized.
          Args:
              self (list): list of baseline parameter values.
              q: Insurance coverage to be optimized.
          
          Returns:
              exp_u (float): Expected utility value for agent.
          """  
          loss = self.y - self.x + q - self.premium(q)                            #net assets in case of loss
          no_loss = self.y - self.premium(q)                                      #net assets in case of no loss
          exp_u = self.p*self.utility(loss) + (1 - self.p)*self.utility(no_loss)  #expected utility
          return exp_u
      
      #Utility without insurance
      def utility_zero(self):
          """ Returns utility without insurance
          Args:
              self (list): list of baseline parameter values.
          
          Returns:
              u_zero (float): Expected utility value for agent with no coverage.
          """  
          loss = self.y - self.x                                                  #net assets in case of loss
          no_loss = self.y                                                        #net assets in case of no loss
          u_zero = self.p*self.utility(loss) + (1 - self.p)*self.utility(no_loss) #expected utility
          return u_zero
      
      #Expected utility with premium independent of coverage and probability of loss
      def varpre_utility(self, var_pre):
          """ Calculates expected utility based on premium as exogenous variable
          Args:
              self (list): list of baseline parameter values.
              var_pre (float) : premium variable paid to insurance company
          
          Returns:
              varpre_u (float): Expected utility value for agent with no coverage.
          """  
          loss = self.y - self.x + self.q - var_pre                           #net assets in case of loss
          no_loss = self.y - var_pre                                      #net assets in case of no loss
          varpre_u = self.p*self.utility(loss) + (1 - self.p)*self.utility(no_loss)  #expected utility
          return varpre_u
      
      #Objective funtion to minimize
      def value_of_choice(self, q):
          """ Returns expected utility to be maximized.
          Args:
              self (list): list of baseline parameter values.
              q: Insurance coverage to be optimized.
          
          Returns:
              neg_u (float): negative value of expected utility value for agent.
          """
          neg_u = -self.exp_utility(q)
          return neg_u
      
      #Solve model for q
      def solve(self):
          """ Solves model by maximizing expected utility of agent through choice of coverage.
          Args:
              self (list): list of baseline parameter values.
              
          Returns:
              q_star (float): optimal coverage.            
              u_star (float): expected utility given the optimal coverage.
          """
         
          # b. call solver 
          q_guess = [0]
          sol = optimize.minimize(self.value_of_choice, q_guess)
  
          # c. save
          self.q = float(sol.x)
          q_star = self.q
          u_star = self.exp_utility(q_star)
          return(q_star, u_star)
      
     
  
      
  