Example #1
0
 def building_match(idx_hhs, idx_blds):        
     resunits = np.array([np.maximum(np.ones(idx_blds.size),(building_set['vacant_units'][idx_blds])),]*idx_hhs.size)
     row_sums = resunits.sum(axis=1)
     probabilities = (resunits) / (np.array([(row_sums),]*idx_blds.size).transpose())
     resources = Resources({"capacity":building_set['vacant_units'][idx_blds],"lottery_max_iterations":50})
     choices = lottery_choices().run(probabilities, resources=resources)
     counter = 0
     for choice in choices:
         if choice == -1:
             household_set['building_id'][idx_hhs[counter]] = -1
         else:
             household_set['building_id'][idx_hhs[counter]] = building_set['building_id'][idx_blds[choice]] 
         counter += 1        
 def mate_match(self, choosers, available_mates, person_set):
     available_mates_age = array([(person_set['age'][available_mates]),]*choosers.size)
     choosers_age = array([(person_set['age'][choosers]),]*available_mates.size).transpose()
     available_mates_edu = array([(person_set['education'][available_mates]),]*choosers.size) #TODO: calc education in terms of years instead of level
     choosers_edu = array([(person_set['education'][choosers]),]*available_mates.size).transpose()
     age_diffs = available_mates_age - choosers_age
     edu_diffs = available_mates_edu - choosers_edu
     match_scores = exp((sqrt((age_diffs**2) + (edu_diffs**2)))*(-.5))
     row_sums = match_scores.sum(axis=1)
     probabilities = (match_scores) / (array([(row_sums),]*available_mates.size).transpose())
     #Select mates according to 'lottery choices' so that capacity can be taken into account (each person can only be chosen once)
     resources = Resources({"capacity":ones(available_mates.size),"lottery_max_iterations":50})
     choices = lottery_choices().run(probabilities, resources=resources)
     #Set each chosen person's household_id to equal the household_id of the chooser
     counter = 0
     for choice in choices:
         person_set['household_id'][available_mates[choice]] = person_set['household_id'][choosers[counter]]
         counter += 1
     logger.log_status("Mate matching complete.")
Example #3
0
    def run(self, probability, resources=None):
        """ Compute choices according to given probability -- Constrain Location Choice procedure.
        'probability' is a 2D numpy array (nobservation x nequations).
        The returned value is a 1D array of choice indices [0, nequations-1] of the length nobservations).
        The argument 'resources' must contain an entry 'capacity'. It is 1D array whose number of elements
        corresponds to the number of choices. 
        Optional entry 'index' (1D or 2D array) gives indices of the choices.
        """
        if probability.ndim < 2:
            raise StandardError, "Argument 'probability' must be a 2D numpy array."
            
        resources.check_obligatory_keys(["capacity"])
        supply = resources["capacity"]
        if not isinstance(supply, ndarray):
            supply = array(supply)
        nsupply = supply.size
#        logger.log_status('Supply.shape:',supply.shape)
#        logger.log_status('supply.sum:', supply.sum())
        max_iter = resources.get("max_iterations", None)
        if max_iter == None:
            max_iter = 100 # default
        
        
        index = resources.get("index", None)
        if index == None:
            index = arange(nsupply)
#        logger.log_status('index.shape:',index.shape)

        neqs = probability.shape[1]
        nobs = probability.shape[0]

        if supply.sum < nobs:
            raise StandardError, "Aggregate Supply Must be Greater than Aggregate Demand."


        if index.ndim <= 1:
            index = repeat(reshape(index, (1,index.shape[0])), nobs)        
        resources.merge({"index":index})
#        logger.log_status('index.shape:',index.shape)


        flat_index = index.ravel()
        unique_index = unique(flat_index)
#        logger.log_status('flat_index.shape:',flat_index.shape)
#        logger.log_status('unique_index.shape',unique_index.shape)
#        logger.log_status(unique_index)
        l = flat_index + 1
        demand = array(ndimage_sum(probability.ravel(), labels=l, index=arange(nsupply)+1))
#        logger.log_status('demand.shape:',demand.shape)
#        logger.log_status('demand.sum:', demand.sum())
#        logger.log_status('probability.sum:',probability.sum())
        #initial calculations
        
        sdratio = ma.filled(supply/ma.masked_where(demand==0, demand),1.0)
#        logger.log_status('sdratio.shape:',sdratio.shape)
        constrained_locations = where(sdratio<1,1,0)
        unconstrained_locations = 1-constrained_locations
        
        # Compute the iteration zero omegas
        
        sdratio_matrix = sdratio[index]
        constrained_locations_matrix = constrained_locations[index]
        unconstrained_locations_matrix = unconstrained_locations[index]
        prob_sum = 1-(probability*constrained_locations_matrix).sum(axis=1)
        omega = (1-(probability*constrained_locations_matrix*sdratio_matrix).sum(axis=1))/ \
                ma.masked_where(prob_sum ==0, prob_sum)
        pi = sdratio_matrix / ma.resize(omega, (nobs,1)) * constrained_locations_matrix + unconstrained_locations_matrix
        average_omega = ma.filled((ma.resize(omega,(nobs,1))*probability).sum(axis=0)/\
                      ma.masked_where(demand[index]==0, demand[index]),0.0)
        number_constrained_locations=zeros((max_iter,))
            # Iterative Constrained Location Procedure
        for i in range(max_iter):
            logger.log_status('Iteration ',i+1, 'Average Omega:',average_omega[0:4])
            # Recompute the constrained locations using iteration zero value of Omega
            constrained_locations_matrix = where(supply[index]<(average_omega*demand[index]),1,0)
            unconstrained_locations_matrix = 1-constrained_locations_matrix
            # Update values of Omega using new Constrained Locations
            prob_sum = 1-(probability*constrained_locations_matrix).sum(axis=1)
            omega = (1-(probability*constrained_locations_matrix*sdratio_matrix).sum(axis=1))/\
                    ma.masked_where(prob_sum ==0, prob_sum)
#            pi = sdratio_matrix / ma.resize(omega, (nobs,1)) * constrained_locations_matrix + unconstrained_locations_matrix       
#            logger.log_status('sdratio_matrix',sdratio_matrix.shape)
#            logger.log_status('constrained_locations_matrix',constrained_locations_matrix.shape)
#            logger.log_status('omega',omega.shape)
#            logger.log_status('unconstrained_locations_matrix',unconstrained_locations_matrix.shape)
#            pi_ta = (sdratio_matrix*constrained_locations_matrix)
#            logger.log_status('pi+ta',pi_ta.shape)
#            pi_tb = ma.resize(omega,(nobs,neqs))*unconstrained_locations_matrix
#            logger.log_status('pi_tb',pi_tb.shape)
            pi_t = (sdratio_matrix*constrained_locations_matrix)+ma.resize(omega,(nobs,neqs))*unconstrained_locations_matrix
#            logger.log_status('pi_tilde:',pi_t.shape)
            # Update the values of average Omegas per alternative
            average_omega = ma.filled((ma.resize(omega,(nobs,1))*probability).sum(axis=0)/
                          ma.masked_where(demand[index]==0, demand[index]),0.0)
            number_constrained_locations[i]= constrained_locations_matrix.sum()
            # Test for Convergence and if Reached, Exit
            if i > 0:
                if number_constrained_locations[i] == number_constrained_locations[i-1]:
                    break
          
        # update probabilities
#        new_probability = ma.filled(probability*ma.resize(omega,(nobs,1))*pi,0.0)
        new_probability = ma.filled(probability*pi_t,0.0)
        choices = lottery_choices().run(new_probability, resources)
        return choices
        
    def run(self, probability, resources=None):
        """ Compute choices according to given probability -- Constrain Location Choice procedure.
        'probability' is a 2D numpy array (nobservation x nequations).
        The returned value is a 1D array of choice indices [0, nequations-1] of the length nobservations).
        The argument 'resources' must contain an entry 'capacity'. It is 1D array whose number of elements
        corresponds to the number of choices.
        Optional entry 'index' (1D or 2D array) gives indices of the choices.
        """
        if probability.ndim < 2:
            raise StandardError, "Argument 'probability' must be a 2D numpy array."

        resources.check_obligatory_keys(["capacity"])
        supply = resources["capacity"]
        if not isinstance(supply, ndarray):
            supply = array(supply)
        nsupply = supply.size

        max_iter = resources.get("max_iterations", None)
        if max_iter == None:
            max_iter = 100 # default

        index = resources.get("index", None)
        if index == None:
            index = arange(nsupply)

        neqs = probability.shape[1]
        nobs = probability.shape[0]

        if index.ndim <= 1:
            index = repeat(reshape(index, (1,index.shape[0])), nobs)
        resources.merge({"index":index})

        flat_index = index.ravel()
        unique_index = unique(flat_index)
        l = flat_index + 1
        demand = array(ndimage_sum(probability.ravel(), labels=l, index=arange(nsupply)+1))

        #initial calculations
        sdratio = ma.filled(supply/ma.masked_where(demand==0, demand),2.0)
        constrained_locations = logical_and(sdratio<1,demand-supply>0.1).astype("int8")
        unconstrained_locations = 1-constrained_locations
        excess_demand = (demand-supply)*constrained_locations
        global_excess_demand = excess_demand.sum()

        # Compute the iteration zero omegas

        sdratio_matrix = sdratio[index]
        constrained_locations_matrix = constrained_locations[index]
# Would like to include following print statements in debug printing
#        logger.log_status('Total demand:',demand.sum())
#        logger.log_status('Total supply:',supply.sum())
        logger.log_status('Global excess demand:',global_excess_demand)
#        logger.log_status('Constrained locations:',constrained_locations.sum())
        unconstrained_locations_matrix = unconstrained_locations[index]
        prob_sum = 1-(probability*constrained_locations_matrix).sum(axis=1)

        # The recoding of prob_sum and omega are to handle extreme values of omega and zero divide problems
        # A complete solution involves stratifying the choice set in the initialization to ensure that
        # there are always a mixture of constrained and unconstrained alternatives in each choice set.

        prob_sum = where(prob_sum==0,-1,prob_sum)
        omega = (1-(probability*constrained_locations_matrix*sdratio_matrix).sum(axis=1))/prob_sum
        omega = where(omega>5,5,omega)
        omega = where(omega<.5,5,omega)
        omega = where(prob_sum<0,5,omega)

# Debug print statements
#        logger.log_status('Minimum omega',minimum(omega))
#        logger.log_status('Maximum omega',maximum(omega))
#        logger.log_status('Median omega',median(omega))
#        logger.log_status('Omega < 0',(where(omega<0,1,0)).sum())
#        logger.log_status('Omega < 1',(where(omega<1,1,0)).sum())
#        logger.log_status('Omega > 30',(where(omega>30,1,0)).sum())
#        logger.log_status('Omega > 100',(where(omega>100,1,0)).sum())
#        logger.log_status('Omega histogram:',histogram(omega,0,30,30))
#        logger.log_status('Excess demand max:',maximum(excess_demand))
#        logger.log_status('Excess demand 0-1000:',histogram(excess_demand,0,1000,20))
#        logger.log_status('Excess demand 0-10:',histogram(excess_demand,0,10,20))

        pi = sdratio_matrix / ma.resize(omega, (nobs,1)) * constrained_locations_matrix + unconstrained_locations_matrix

        omega_prob = ma.filled(ma.resize(omega,(nobs,1))*probability,0.0)
        average_omega_nom = array(ndimage_sum(omega_prob, labels=index+1, index=arange(nsupply)+1))

        average_omega = ma.filled(average_omega_nom/
                      ma.masked_where(demand==0, demand), 0.0)

#        logger.log_status('Total demand:',new_demand.sum())
#        logger.log_status('Excess demand:',excess_demand)
        number_constrained_locations=zeros((max_iter,))
        # Iterative Constrained Location Procedure
        for i in range(max_iter):
            logger.log_status()
            logger.log_status('Constrained location choice iteration ',i+1)
            # Recompute the constrained locations using preceding iteration value of Omega
            constrained_locations = where((average_omega*demand-supply>0.1),1,0)
            unconstrained_locations = 1-constrained_locations
            constrained_locations_matrix = constrained_locations[index]
            unconstrained_locations_matrix = unconstrained_locations[index]
#            logger.log_status('supply.shape,average_omega.shape,demand.shape',supply.shape,average_omega.shape,demand.shape)
#            logger.log_status('constrained_locations_matrix',constrained_locations_matrix)
#            logger.log_status('constrained_locations_matrix.shape',constrained_locations_matrix.shape)
#            logger.log_status('unconstrained_locations_matrix',unconstrained_locations_matrix)
            # Update values of Omega using new Constrained Locations
            prob_sum = 1-(probability*constrained_locations_matrix).sum(axis=1)
            prob_sum = where(prob_sum==0,-1,prob_sum)
            omega = (1-(probability*constrained_locations_matrix*sdratio_matrix).sum(axis=1))/prob_sum
            omega = where(omega>5,5,omega)
            omega = where(omega<.5,5,omega)
            omega = where(prob_sum<0,5,omega)
            pi = sdratio_matrix / ma.resize(omega, (nobs,1)) * constrained_locations_matrix + unconstrained_locations_matrix
            # Update the values of average Omegas per alternative
            omega_prob = ma.filled(ma.resize(omega,(nobs,1)), 1.0)*probability
            average_omega_num = array(ndimage_sum(omega_prob, labels=index+1, index=arange(nsupply)+1))

            average_omega = ma.filled(average_omega_num/
                      ma.masked_where(demand==0, demand), 0.0)

            number_constrained_locations[i] = constrained_locations.sum()
            new_probability = ma.filled(probability*ma.resize(omega,(nobs,1))*pi,0.0)
            new_demand = array(ndimage_sum(new_probability.ravel(), labels=l, index=arange(nsupply)+1))
            excess_demand = (new_demand-supply)*constrained_locations
            global_excess_demand = excess_demand.sum()
#            logger.log_status('Total demand:',new_demand.sum())
            logger.log_status('Global excess demand:',global_excess_demand)
#            logger.log_status('Constrained locations:', number_constrained_locations[i])
#            logger.log_status('Minimum omega',minimum(omega))
#            logger.log_status('Maximum omega',maximum(omega))
#            logger.log_status('Median omega',median(omega))
#            logger.log_status('Omega < 0',(where(omega<0,1,0)).sum())
#            logger.log_status('Omega < 1',(where(omega<1,1,0)).sum())
#            logger.log_status('Omega > 30',(where(omega>30,1,0)).sum())
#            logger.log_status('Omega > 100',(where(omega>100,1,0)).sum())
#            logger.log_status('Omega histogram:',histogram(omega,0,30,30))
#            logger.log_status('Excess demand max:',maximum(excess_demand))
#            logger.log_status('Excess demand 0-5:',histogram(excess_demand,0,5,20))
#            logger.log_status('Excess demand 0-1:',histogram(excess_demand,0,1,20))
            # Test for Convergence and if Reached, Exit
            if i > 0:
                if number_constrained_locations[i] == number_constrained_locations[i-1]:
                    logger.log_status()
                    logger.log_status('Constrained choices converged.')
                    break

        # update probabilities
        new_probability = ma.filled(probability*ma.resize(omega,(nobs,1))*pi,0.0)
        choices = lottery_choices().run(new_probability, resources)
        return choices
Example #5
0
    def run(self, probability, resources=None):
        """ Compute choices according to given probability -- Constrain Location Choice procedure.
        'probability' is a 2D numpy array (nobservation x nequations).
        The returned value is a 1D array of choice indices [0, nequations-1] of the length nobservations).
        The argument 'resources' must contain an entry 'capacity'. It is 1D array whose number of elements
        corresponds to the number of choices. 
        Optional entry 'index' (1D or 2D array) gives indices of the choices.
        """
        if probability.ndim < 2:
            raise StandardError, "Argument 'probability' must be a 2D numpy array."
            
        resources.check_obligatory_keys(["capacity"])
        supply = resources["capacity"]
        if not isinstance(supply, ndarray):
            supply = array(supply)
        nsupply = supply.size
#        logger.log_status('Supply.shape:',supply.shape)
#        logger.log_status('supply.sum:', supply.sum())
        max_iter = resources.get("max_iterations", None)
        if max_iter == None:
            max_iter = 100 # default
        
        
        index = resources.get("index", None)
        if index == None:
            index = arange(nsupply)
#        logger.log_status('index.shape:',index.shape)

        neqs = probability.shape[1]
        nobs = probability.shape[0]

        if supply.sum < nobs:
            raise StandardError, "Aggregate Supply Must be Greater than Aggregate Demand."


        if index.ndim <= 1:
            index = repeat(reshape(index, (1,index.shape[0])), nobs)        
        resources.merge({"index":index})
#        logger.log_status('index.shape:',index.shape)


        flat_index = index.ravel()
        unique_index = unique(flat_index)
#        logger.log_status('flat_index.shape:',flat_index.shape)
#        logger.log_status('unique_index.shape',unique_index.shape)
#        logger.log_status(unique_index)
        l = flat_index + 1
        demand = array(ndimage_sum(probability.ravel(), labels=l, index=arange(nsupply)+1))
#        logger.log_status('demand.shape:',demand.shape)
#        logger.log_status('demand.sum:', demand.sum())
#        logger.log_status('probability.sum:',probability.sum())
        #initial calculations
        
        sdratio = ma.filled(supply/ma.masked_where(demand==0, demand),1.0)
#        logger.log_status('sdratio.shape:',sdratio.shape)
        constrained_locations = where(sdratio<1,1,0)
        unconstrained_locations = 1-constrained_locations
        
        # Compute the iteration zero omegas
        
        sdratio_matrix = sdratio[index]
        constrained_locations_matrix = constrained_locations[index]
        unconstrained_locations_matrix = unconstrained_locations[index]
        prob_sum = 1-(probability*constrained_locations_matrix).sum(axis=1)
        omega = (1-(probability*constrained_locations_matrix*sdratio_matrix).sum(axis=1))/ \
                ma.masked_where(prob_sum ==0, prob_sum)
        pi = sdratio_matrix / ma.resize(omega, (nobs,1)) * constrained_locations_matrix + unconstrained_locations_matrix
        average_omega = ma.filled((ma.resize(omega,(nobs,1))*probability).sum(axis=0)/\
                      ma.masked_where(demand[index]==0, demand[index]),0.0)
        number_constrained_locations=zeros((max_iter,))
            # Iterative Constrained Location Procedure
        for i in range(max_iter):
            logger.log_status('Iteration ',i+1, 'Average Omega:',average_omega[0:4])
            # Recompute the constrained locations using iteration zero value of Omega
            constrained_locations_matrix = where(supply[index]<(average_omega*demand[index]),1,0)
            unconstrained_locations_matrix = 1-constrained_locations_matrix
            # Update values of Omega using new Constrained Locations
            prob_sum = 1-(probability*constrained_locations_matrix).sum(axis=1)
            omega = (1-(probability*constrained_locations_matrix*sdratio_matrix).sum(axis=1))/\
                    ma.masked_where(prob_sum ==0, prob_sum)
#            pi = sdratio_matrix / ma.resize(omega, (nobs,1)) * constrained_locations_matrix + unconstrained_locations_matrix       
#            logger.log_status('sdratio_matrix',sdratio_matrix.shape)
#            logger.log_status('constrained_locations_matrix',constrained_locations_matrix.shape)
#            logger.log_status('omega',omega.shape)
#            logger.log_status('unconstrained_locations_matrix',unconstrained_locations_matrix.shape)
#            pi_ta = (sdratio_matrix*constrained_locations_matrix)
#            logger.log_status('pi+ta',pi_ta.shape)
#            pi_tb = ma.resize(omega,(nobs,neqs))*unconstrained_locations_matrix
#            logger.log_status('pi_tb',pi_tb.shape)
            pi_t = (sdratio_matrix*constrained_locations_matrix)+ma.resize(omega,(nobs,neqs))*unconstrained_locations_matrix
#            logger.log_status('pi_tilde:',pi_t.shape)
            # Update the values of average Omegas per alternative
            average_omega = ma.filled((ma.resize(omega,(nobs,1))*probability).sum(axis=0)/
                          ma.masked_where(demand[index]==0, demand[index]),0.0)
            number_constrained_locations[i]= constrained_locations_matrix.sum()
            # Test for Convergence and if Reached, Exit
            if i > 0:
                if number_constrained_locations[i] == number_constrained_locations[i-1]:
                    break
          
        # update probabilities
#        new_probability = ma.filled(probability*ma.resize(omega,(nobs,1))*pi,0.0)
        new_probability = ma.filled(probability*pi_t,0.0)
        choices = lottery_choices().run(new_probability, resources)
        return choices