How to add fairshare distribution
AnsweredDear Gurobi Community,
I was unable to include the fairshare rule, as the costs and weights are the same and the objective function is a cost minimization, the solution ends up being random.
for example: when there is insufficient supply and I don’t have prioritization of any kind to meet demand in different regions, with fairshare I expect that all regions to be supplied in proportionality to their demand, but what is happening all the supply is fulfilling a single region, in terms of cost minimization it is the same to supply only one or all regions proportionally.
The way that I have been working so far but have not yet managed to get the expected result, is to split the demand for each region based on “slice_factor” and adding weights to this slice of demand and at each “slice_factor” iteration the weight decreases. For example: The slice factor of 3 is specified, each demand is split into 3 slices. In the first iteration, the demand quantity of the first slice of all demands is met, and so on.
But this doesn't seem to me to be the best way to go, because (1) it's still not generating the desired result (2) it distorts the unfulfilled costs (by adding more weight) (3) depending on the demand quantity between the regions, a third slice in D1 could be more significant than the second slice in D2 (assuming D2 is very small quantity), for example.
# Sets Parameters, respectively
DC = ['DC1'] # source i
region = ['R1','R2','R3'] # destination j
T = [1,2,3] # time peridos t
product = ['A','B']
slice_factor = range(3)
# to create a decision variable
m = gp.Model('FairShare')
flow_out = m.addVars(product,DC,region,T,slice_factor, vtype=GRB.INTEGER, name = 'flow_out') #Set as interger
# Weight to fulfill split demands in k
weight = m.addVars(slice_factor, name = 'weight')
for k in slice_factor:
weight[k] = max(slice_factor)+1k
m.update()
# Calculation of the unfulfilled quantity
unfulfilmet = {}
for h in product:
for i in DC:
for j in region:
for t in T:
for k in slice_factor:
if t + lead_time[i,j] <= max(T):
unfulfilmet[h,i,j,t + lead_time[i,j],k] = (n_demand[h,j,t + lead_time[i,j]]/(max(slice_factor)+1)  flow_out[h,i,j,t + lead_time[i,j],k]*lot_size[j])*weight[k]
m.update()

Hi Beatriz,
I am not sure if I understood the problem correctly, but here is an idea:
Add constraint: (S_i is variable for the supply of region i, D_i is the constant for the demand of region i)
S_i/D_i  S_j/D_j  slack_ij = 0 for all i, j in regionsInclude in objective function the minimization of the sum of the slacks with an appropriate coefficient.
I expect to work as you described: " I expect that all regions to be supplied in proportionality to their demand".
0 
Hi Michel,
Thanks for your reply! Sorry if I didn't make myself clear
From what I understood, what you're referring to as "slack" is what I mean by unfulfilled quantity and I'm adding it to the cost minimization formula. Actually, I'm multiplying this "slack" by a cost of no fulfillment. However, as this cost is the same for all 3 regions, it doesn't matter if it serves only 2 regions completely, or all 3 regions partially. For example:
Supply: 300 units
Unfulfillment cost: 10 $/unitScenario 1 Demand Fulfilment Slack Cost Region 1 100 100 0 0 Region 2 200 200 0 0 Region 3 300 0 300 3000 Sum 600 300 300 3000 Fair Share Scenario Demand FairShare ratio Fulfilment Slack Cost Region 1 100 17% 50 50 500 Region 2 200 33% 100 100 1000 Region 3 300 50% 150 150 1500 Sum 600 100% 300 300 3000 0 
Implementing a fairshare allocation in your optimization problem, especially when dealing with cost minimization and equal weights, can indeed be challenging. The method you've described attempts to ensure fair distribution by splitting demand into slices and prioritizing them differently, but as you've observed, it comes with drawbacks. Let's explore an alternative approach that might help achieve your goals more effectively.
Alternative Approach: Proportional Allocation
Instead of slicing the demand and applying decreasing weights, consider directly incorporating a fairshare or proportional allocation constraint into your model. This method aims to enforce that each region receives a share of the supply proportional to its demand, subject to the total available supply.
The key idea here is to calculate the total available supply and the total demand across all regions. Then, for each region, you enforce that the ratio of the supply received to the total supply available is as close as possible to the ratio of the region's demand to the total demand.
Step 1: Define Total Supply and Demand
Let's calculate the total supply Stotal and total demand Dtotal:
 Stotal=∑i∈DCsupplyi
 Dtotal=∑j∈regiondemandj
Step 2: Proportional Allocation Constraints
For each region j, you want the proportion of the total supply it receives (Xj/Stotal) to be as close as possible to its proportion of the total demand (demandj/Dtotal). This can be expressed as a constraint for each region. However, achieving exact proportions might not always be feasible, especially if the total supply is less than the total demand. In such cases, you can relax the constraints to aim for proportionality within the limits of available supply.
Implementation
To integrate this into your model, you could add constraints that minimize the deviation from these proportional targets. This would involve introducing new decision variables to represent the proportion of supply allocated to each region and setting the objective to minimize the sum of absolute deviations from the target proportions.
Here is a conceptual overview of how this could be formulated:

Define Proportion Variables: For each region j, define a variable that represents the proportion of the total supply allocated to that region.

Add Proportional Allocation Constraints: For each region , add constraints to ensure is as close as possible to demandj/Dtotal, within the limits of the available supply.

Objective Function: Adjust the objective function to minimize the sum of the absolute deviations from the target proportions, alongside your existing cost minimization goals. This may involve a tradeoff parameter to balance cost minimization with fair distribution.
This approach requires careful formulation to ensure the model remains linear (if that's a requirement) and might involve additional decision variables and constraints to capture the proportional allocation effectively. It's also essential to consider how this method aligns with your overall objectives and constraints.
0 
Hi Beatriz,
The slack variable here is a new variable that means the difference between the supply/demand proportion of region I and J.
Add constraint: (S_i is variable for the supply of region i, D_i is the constant for the demand of region i)
S_i/D_i  S_j/D_j + slack_ij <= 0 for all i, j in regionsIn your examples:
Scenario 1 Demand Fulfilment Slack Cost Region 1 100 100 0 0 Region 2 200 200 0 0 Region 3 300 0 300 3000 Sum 600 300 300 3000 0/300  (100/100) + Slack_3,1 <= 0 > Slack_3,1 = 1
0/300  (200/200) + Slack_3,1 <= 0 > Slack_3,2 = 1
All other slacks = 0. The sum of all slacks will be 2, which you will penalize in the objective function.Fair Share Scenario Demand FairShare ratio Fulfilment Slack Cost Region 1 100 17% 50 50 500 Region 2 200 33% 100 100 1000 Region 3 300 50% 150 150 1500 Sum 600 100% 300 300 3000 Here, all slacks are zero. Example:
(150/300)  (100/200) + Slack_3,2 <= 0 > Slack_3,2 = 00 
Hi Michel,
Thanks for your reply... I see what you mean, by applying the rationale it worked.
The only thing is that in my current model I have discrete variables which are the lot sizes for transfer. From what I understood and applied from your suggestion, the slack is forced to be zero, but when I have lot sizes the Fulfilment (discrete) will not necessarily be equal to the Supply*FairShare ratio (continuous) and the slack may even be greater than zero.
To solve this, I created two variables ('Slack 1' and 'Slack 2') that cannot be negative. As a constraint, the difference between these variables (Slack 1  Slack 2) must be equal to the Fulfilment  Supply*FairShare ratio. In addition, the sum of the variables is part of the objective function, so that the Slack should be as small as possible.
Thanks for your support, it was very helpful!
0
Please sign in to leave a comment.
Comments
5 comments