<jupyter_start><jupyter_text>Resourcing: Solar panel cells  Introduction In this notebook we will use: - The Python open source Linear Programming library [PuLP](http://pythonhosted.org/PuLP/) to model and solve linear problems- The Python open source data analysis library [Pandas] (https://pandas.pydata.org/) to show the results- The IPython model display [Display] (https://ipython.org/ipython-doc/3/api/generated/IPython.display.html) to format the output - The Python numpy library [Numpy] (http://www.numpy.org/) to perform basic operations. We wil learn how to model problems in a way that scales to hundreds or thousands of variables and how to get all valuable information from the results generated by PuLP.  Problem DefinitionWeyland Corp is a British firm that manufactures solar panel cells. This firm supplies three differnt types of cell called: fast, normal and ultra. There are three operations involved in the manufacturing process. The following table describes the hours/month required to manufacture each model: **Table 1:** hours/month requirements| Operation|   Fast (hours/month) |   Normal (hours/month) |  Ultra (hours/month)| |----------|----------------------|------------------------|---------------------||  1       |        1             |           3            |        2            ||  2       |        2             |           0            |        3            ||  3       |        1             |           4            |        0            |And the following table describes the total hours available for each operation:**Table 2:** Total hours/month available| Operation | Hours/Month || ----------| ------------||     1     |     400     ||     2     |     600     ||     3     |     600     |The profit per each model is specified in the following table:**Table 3:** Unit of profit per model| Model     | Profit/Unit || ----------| ------------||  Normal   |     30      ||  Economic |     20      ||  Luxury   |     40      |  Problem Model Decision variablesThe decision variables are: $x_1:$Units of Fast cells / month$x_2:$Units of Normal cells / month$x_3:$Units of Ultra cells / month Objective FunctionThe objective function is:$\max z=30x_1+20x_2+40x_3$ ConstraintsSubject to the following constraints:$x_1+3x_2+2x_3 \leq  400$$2x_1+0x_2+3x_3 \leq  600$$x_1+4x_2+0x_3 \leq  600$  Problem Solution with PulpLet us solve the problem with pulp. We start by importing PULP and instantiating the problem:<jupyter_code>import pandas as pd
import numpy as np
from IPython.display import display, Markdown
import pulp
# Instantiate our problem class
model = pulp.LpProblem("Maximising profits for Weyland Corp", pulp.LpMaximize)<jupyter_output><empty_output><jupyter_text>In this problem, we have three decision variables. We could name them individually like in the first example, but this does not scale (imagine we had hundreds). Instead we will use lists and tuple lists which can be really useful to minimise the problem configuration. First we create the lists:<jupyter_code># Construct our decision variable lists
cell_types = ['fast', 'normal', 'ultra']<jupyter_output><empty_output><jupyter_text>The decision variables have the same characteristics (lower bound of 0, continuous variables). We can use the  LpVariable object's dict functionality to create the variables from the tuples. The good thing about tuples is that we could add more dimensions (eg cell categories) and still create all decision variables in one line of code.<jupyter_code>cell_units = pulp.LpVariable.dicts("cells",
                                     (i for i in cell_types),
                                     lowBound=0,
                                     cat='Continuous')<jupyter_output><empty_output><jupyter_text>PuLP provides an lpSum vector calculation for the sum of a list of linear expressions.  Although we only have 6 decision variables, we will use lpSum to construct the expression using this feature, again for the sake of scalibility.<jupyter_code># Technological Coefficients:
unit_profits = [30, 20, 40]
# Objective Function

model += (
    pulp.lpSum([
        unit_profits[i] * cell_units[cell_types[i]]
        for i in range(len(cell_types))])
)<jupyter_output><empty_output><jupyter_text>Now we add the constraints using the tuplets to identify the coefficients<jupyter_code># Operations 
operations = ["Operation 1", "Operation 2", "Operation 3"]
# Constraints
A=[[1, 3, 2], #Coefficients of the first constraint
   [2, 0, 3], #Coefficients of the second constraint
   [1, 4, 0]] #Coefficients of the third constraint

# Capacities
b = [400, 600, 600]
 #Iterate matrix raws
for i in range(len(A)):
    model += pulp.lpSum([
        A[i][j] * cell_units[cell_types[j]] 
        for j in range(len(cell_types))]) <= b[i] , operations[i]    
#note that in this case all constraints are of type less or equal
# Solve our problem
model.solve()

pulp.LpStatus[model.status]
total_profit = pulp.value(model.objective)
display(Markdown("Total profit is %0.2f €"%total_profit))

display(Markdown("The following table shows the decision variables: "))
var_df = pd.DataFrame.from_dict(cell_units, orient="index", 
                                columns = ["Variables"])

# First we add the solution. We apply a lambda function to get only two decimals:
var_df["Solution"] = var_df["Variables"].apply(lambda item: item.varValue)
# We do the same for the reduced cost:
var_df["Reduced cost"] = var_df["Variables"].apply(lambda item: item.dj)

display(var_df)


const_dict = dict(model.constraints)
con_df = pd.DataFrame.from_records(list(const_dict.items()), exclude=["Expression"], columns=["Constraint", "Expression"])
#Now we add columns for the solution, the slack and shadow price

con_df["Right Hand Side"] = con_df["Constraint"].apply(lambda item: -const_dict[item].constant)
con_df["Slack"] = con_df["Constraint"].apply(lambda item: const_dict[item].slack)
con_df["Shadow Price"] = con_df["Constraint"].apply(lambda item: const_dict[item].pi)


display(Markdown("The following table shows the constraints: "))
display(con_df)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11080196399345335, 'fraction_numerical': 0.016857610474631753, 'mean_word_length': 3.2974683544303796, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 15, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '413923', 'license': 'MIT', 'n_tokens_mistral': 1761, 'n_tokens_neox': 1660, 'n_words': 638, 'path': 'docs/source/CLP/solved/Manufacturing solar cell panels (Solved CBC).ipynb', 'repo_name': 'ffraile/operations-research-notebooks', 'size': '6110'}