OPTIMASI

UTS OPTIMASI


Kontak : \(\downarrow\)
Email
Instagram https://www.instagram.com/m_naufalardiansyah/
RPubs https://rpubs.com/muhammad_naufal/

SOAL 1

Find the maximum solution to \(Z=4x+3y\)

Suppose that the objective function is subject to the following constraints:

\[ \begin{align} x≥0 \\ y≥2 \\ 2y≤25-x \\ 4y≤2x-8 \\ y≤2x-5 \\ \end{align} \]

Solve these problems using mathematical model and R packages (please explain it step-by-step).

## (0.0, 25.0)
## (0.0, 11.0)

\[ \begin{align*} &Line \space 1 & & Line \space 2& \\ 4y & \leq 2x-8 & y & \geq 2 \\ 2y & \leq 25-x & y & \geq 2 \\ 2y & \leq 25-x & 4y & \leq 2x-8 \\ \end{align*} \]

PERHITUNGAN Z

\[ Z = 4x + 3y\]

1)

\[ \begin{align*} 4y & \leq 2x-8 \space and \space y \geq 2 \\ {x-4 \over 2} & = 2 \\ 4 &= x-4 \\ x &= 8 \\ y &= 2 \\ Z & =(4\times 8)+ (3\times 2)=38 \end{align*} \]

2)

\[ \begin{align*} 4y & \leq 2x-8 \space and \space 2y \leq 25-x \\ {x-4 \over 2} & = {25-x \over 2} \\ 2x-8 &= 50-2x \\ 4x & = 58 \\ x &= 14.5 \\ y &= 5.25 \\ Z & =(4\times 14.5)+ (3\times 5.25)=73.75 \end{align*} \]

3)

\[ \begin{align*} 2y & \leq 25-x \space and \space y \geq 2 \\ {25-x \over 2} & = 2 \\ 25-x &= 4 \\ x &= 21 \\ y &= 2 \\ Z & =(4\times 21)+ (3\times 2)=90 \end{align*} \]

Maka dari 3 hasil di atas yang menghasilkan nilai maximum adalah \(2y \leq 25-x \space and \space y \geq 2\) dan menghasilkan nilai \(90\).

Untuk perhitungan R adalah sebagai berikut :

library(lpSolve)

maxim <- c(4,3)
LHS <- matrix(c(1,2,
                -2,4,
                -2,1,
                0,1)
              ,ncol=2, byrow=TRUE)
arah_kendala <- c("<=","<=","<=",">=")
RHS <- c(25,-8,-5,2)

# Penyelesaian
model <- lp ("max",
            maxim,
            LHS,
            arah_kendala,
            RHS,
            compute.sens = TRUE)

print(model)
## Success: the objective function is 90
model$solution
## [1] 21  2

SOAL 2

Let say you are working as consultant for a boutique car manufacturer, producing luxury cars. They run on one-month (30 days) cycles, we have one cycle to show we can provide value. There is one robot, 2 engineers and one detailer in the factory. The detailer has some holiday off, so only has 21 days available.

The 2 cars need different time with each resource:

Resource time Car A Car B
Robot 3 days 4 days
Engineer 5 days 6 days
Detailer 1.5 days 3 days

Car A provides $30,000 profit, whilst Car B offers $45,000 profit. At the moment, they produce 4 of each car per month, for $300,000 profit. Not bad at all, but we think we can do better for them.

## (0.0, 25.0)
## (0.0, 11.0)

Untuk perhitungan Rnya adalah sebagai berikut :

library(lpSolve)

maxim_1 <- c(30000,45000)
LHS <- matrix(c(3,4,
                5,6,
                1.5,3)
              ,ncol=2, byrow=TRUE)
arah_kendala <- c("<=","<=","<=")
RHS <- c(30,60,21)

# Penyelesaian
model <- lp ("max",
            maxim_1,
            LHS,
            arah_kendala,
            RHS,
            compute.sens = TRUE)

print(model)
## Success: the objective function is 330000
model$solution
## [1] 2 6
library(gMOIP)
p1 <- plotPolytope(
   LHS,
   RHS,
   maxim_1,
   type = rep("c", ncol(LHS)),
   crit = "max",
   faces = rep("c", ncol(LHS)),
   plotFaces = TRUE,
   plotFeasible = TRUE,
   plotOptimum = FALSE,
   labels = NULL
) + ggplot2::ggtitle("Feasible region ")
p1

SOAL 3

Let say you would like to make some sausages and you have the following ingredients available:

Ingredient Cost ($/kg) Availability (kg)
Chicken 4.32 30
Wheat 2.46 20
Starch 1.86 17

Assume that you will make 2 types of sausage:

  • Economy (>40% Chicken)
  • Premium (>60% Chicken)
  • One sausage is 50 grams (0.05 kg)

According to government regulations of Indonesia:

  • The most starch you can use in your sausages is 25%.
  • You have a contract with a butcher, and have already purchased 23 kg Chicken, that must go in your sausages.
  • You have a demand for 350 economy sausages and 500 premium sausages.

So, please figure out how to optimize the cost effectively to blend your sausages.

import pulp

model = pulp.LpProblem("Cost minimising blending problem", pulp.LpMinimize)
## C:\Users\DELLA\AppData\Roaming\Python\Python39\site-packages\pulp\pulp.py:1352: UserWarning: Spaces are not permitted in the name. Converted to '_'
##   warnings.warn("Spaces are not permitted in the name. Converted to '_'")
sausage_types = ['economy', 'premium']
ingredients = ['chicken','wheat','starch']

ing_weight = pulp.LpVariable.dicts("weight kg",
                                     ((i, j) for i in sausage_types for j in ingredients),
                                     lowBound=0,
                                     cat='Continuous')
# Objective Function
model += (
    pulp.lpSum([
        4.32 * ing_weight[(i, 'chicken')]
        + 2.46 * ing_weight[(i, 'wheat')]
        + 1.86 * ing_weight[(i, 'starch')]
        for i in sausage_types])
)
# Constraints
# 350 economy and 500 premium sausages at 0.05 kg
model += pulp.lpSum([ing_weight['economy', j] for j in ingredients]) == 350 * 0.05
model += pulp.lpSum([ing_weight['premium', j] for j in ingredients]) == 500 * 0.05

# Economy has >= 40% chicken, premium >= 60% chicken
model += ing_weight['economy', 'chicken'] >= (
    0.4 * pulp.lpSum([ing_weight['economy', j] for j in ingredients]))

model += ing_weight['premium', 'chicken'] >= (
    0.6 * pulp.lpSum([ing_weight['premium', j] for j in ingredients]))

# Sausages must be <= 25% starch
model += ing_weight['economy', 'starch'] <= (
    0.25 * pulp.lpSum([ing_weight['economy', j] for j in ingredients]))

model += ing_weight['premium', 'starch'] <= (
    0.25 * pulp.lpSum([ing_weight['premium', j] for j in ingredients]))

# We have at most 30 kg of chicken, 20 kg of wheat and 17 kg of starch available
model += pulp.lpSum([ing_weight[i, 'chicken'] for i in sausage_types]) <= 30
model += pulp.lpSum([ing_weight[i, 'wheat'] for i in sausage_types]) <= 20
model += pulp.lpSum([ing_weight[i, 'starch'] for i in sausage_types]) <= 17

# We have at least 23 kg of chicken to use up
model += pulp.lpSum([ing_weight[i, 'chicken'] for i in sausage_types]) >= 23
# Solve our problem
model.solve()
## 1
pulp.LpStatus[model.status]
## 'Optimal'
for var in ing_weight:
    var_value = ing_weight[var].varValue
    print ("The weight of {0} in {1} sausages is {2} kg".format(var[1], var[0], var_value))
## The weight of chicken in economy sausages is 7.0 kg
## The weight of wheat in economy sausages is 6.125 kg
## The weight of starch in economy sausages is 4.375 kg
## The weight of chicken in premium sausages is 16.0 kg
## The weight of wheat in premium sausages is 2.75 kg
## The weight of starch in premium sausages is 6.25 kg
total_cost = pulp.value(model.objective)

print ("The total cost is €{} for 350 economy sausages and 500 premium sausages".format(round(total_cost, 2)))
## The total cost is €140.96 for 350 economy sausages and 500 premium sausages

SOAL 4

Please visualize a contour plot of the following function:

\[f(x,y)=x^2+y^2+3xy\]

How Coordinate Descent Works

f <- function(x, y) {
        x^2 + y^2 + 3* x * y
}
n <- 30
xpts <- seq(-1.5, 1.5, len = n)
ypts <- seq(-1.5, 1.5, len = n)
gr <- expand.grid(x = xpts, y = ypts)
feval <- with(gr, matrix(f(x, y), nrow = n, ncol = n))
par(mar = c(5, 4, 1, 1))
contour(xpts, ypts, feval, nlevels = 20, xlab = "x", ylab = "y")
points(-1, -1, pch = 19, cex = 2)
abline(h = -1)

How Steepest Descent Works

import numpy as np
import numpy.linalg as la

import scipy.optimize as sopt

import matplotlib.pyplot as pt
from mpl_toolkits.mplot3d import axes3d

def f(x):
    return x[0]**2 + x[1]**2 + 3* x[0] * x[1]

def df(x):
    return np.array([2*x[0]+3*x[1], 3*x[0]+2*x[1]])
fig = pt.figure()
ax = fig.gca(projection="3d")
## <string>:1: MatplotlibDeprecationWarning: Calling gca() with keyword arguments was deprecated in Matplotlib 3.4. Starting two minor releases later, gca() will take no keyword arguments. The gca() function should only be used to get the current axes, or if no axes exist, create new axes with default keyword arguments. To create a new axes with non-default arguments, use plt.axes() or plt.subplot().
xmesh, ymesh = np.mgrid[-2:2:50j,-2:2:50j]
fmesh = f(np.array([xmesh, ymesh]))
ax.plot_surface(xmesh, ymesh, fmesh)

How Newton Method Works

import numpy as np
import matplotlib.pyplot as plt

def Newton_Raphson_Optimize(Grad, Hess, x,y, epsilon=0.000001, nMax = 200):
    #Initialization
    i = 0
    iter_x, iter_y, iter_count = np.empty(0),np.empty(0), np.empty(0)
    error = 10
    X = np.array([x,y])
    
    #Looping as long as error is greater than epsilon
    while np.linalg.norm(error) > epsilon and i < nMax:
        i +=1
        iter_x = np.append(iter_x,x)
        iter_y = np.append(iter_y,y)
        iter_count = np.append(iter_count ,i)   
        print(X) 
        
        X_prev = X
        X = X - np.linalg.inv(Hess(x,y)) @ Grad(x,y)
        error = X - X_prev
        x,y = X[0], X[1]
          
    return X, iter_x,iter_y, iter_count


def f_2(x,y):
    return x**2 + y**2 + 3*x*y

def Grad_f_2(x,y):
    g1 = 2*x+3*y
    g2 = 3*x+2*y
    return np.array([g1,g2])

def Hessian_f_2(x,y):
    return np.array([[.02,0],[0,-.2]]) 

root_nr,iter_x_nr,iter_y_nr, iter_count_nr = Newton_Raphson_Optimize(Grad_f_2,Hessian_f_2,-2,-.01, nMax = 25)
## [-2.   -0.01]
## [199.5  -30.11]
## [-15234.     2661.29]
## [1108972.5  -199235.81]
## [-79902906.    14442993.59]
## [ 5.74393866e+09 -1.03967066e+09]
## [-4.12699328e+11  7.47227026e+10]
## [ 2.96488281e+13 -5.36854019e+12]
## [-2.12995295e+15  3.85678479e+14]
## [ 1.5301357e+17 -2.7706831e+16]
## [-1.09923188e+19  1.99042841e+18]
## [ 7.8967530e+20 -1.4299007e+20]
## [-5.67293443e+22  1.02722387e+22]
## [ 4.07536927e+24 -7.37945538e+23]
## [-2.92769727e+26  5.30131382e+25]
## [ 2.10322323e+28 -3.80840139e+27]
## [-1.51093079e+30  2.73591069e+29]
## [ 1.08543488e+32 -1.96544600e+31]
## [-7.79763626e+33  1.41195325e+33]
## [ 5.60173002e+35 -1.01433058e+35]
## [-4.02421685e+37  7.28683139e+36]
## [ 2.89094997e+39 -5.23477382e+38]
## [-2.07682440e+41  3.76059984e+40]
## [ 1.49196618e+43 -2.70157061e+42]
## [-1.07181092e+45  1.94077650e+44]
x = np.linspace(-3,3,100)
y = np.linspace(-1,1,100)
X, Y = np.meshgrid(x, y)
Z = f_2(X, Y)

#Angles needed for quiver plot
anglesx_nr = iter_x_nr[1:] - iter_x_nr[:-1]
anglesy_nr = iter_y_nr[1:] - iter_y_nr[:-1]


fig = plt.figure(figsize = (16,8))

#Surface plot
ax = fig.add_subplot(1, 2, 1, projection='3d')
ax.plot_surface(X,Y,Z,rstride = 5, cstride = 5, cmap = 'jet', alpha = .4, edgecolor = 'none' )
ax.plot(iter_x_nr,iter_y_nr, f_2(iter_x_nr,iter_y_nr),color = 'darkblue', marker = 'o', alpha = .4, label = 'Newton')
ax.legend()

#Rotate the initialization to help viewing the graph
#ax.view_init(45, 280)
ax.set_xlabel('x')
ax.set_ylabel('y')

#Contour plot
ax = fig.add_subplot(1, 2, 2)
ax.contour(X,Y,Z, 60, cmap = 'jet')
#Plotting the iterations and intermediate values
## <matplotlib.contour.QuadContourSet object at 0x000000003F59B7C0>
ax.scatter(iter_x_nr,iter_y_nr,color = 'darkblue', marker = 'o',  label = 'Newton')
ax.quiver(iter_x_nr[:-1], iter_y_nr[:-1], anglesx_nr, anglesy_nr, scale_units = 'xy', angles = 'xy', scale = 1, color = 'darkblue', alpha = .3)
ax.legend()

ax.set_title('Newton Method')

plt.show()

How Conjugate Gradient Works

import numpy as np
import matplotlib.pyplot as plt
import math
from math import *

def f(x1, x2):
    return x1**2 + x2**22 + 3* x1 * x2
def gradient(x1, x2):
    return np.array([2*x1+3*x2, 3*x1+2*x2])
def norm(matrice_1x2):
    n_line = matrice_1x2.shape[0]
    N = 0
    for i in range(n_line):
        N += matrice_1x2[i]**2
    return math.sqrt(N)
x1, x2 = 50,50
t = 0.1
epsilon = pow(10,-6)
grad_f = gradient(x1, x2)
n_grad = norm(grad_f)
i = 1
evolution_X1_X2 = [[x1, x2]]

while n_grad > epsilon:
    
    direction = -grad_f
    x1, x2 = x1 + t*direction[0], x2 + t*direction[1] 
    evolution_X1_X2 = np.vstack((evolution_X1_X2, [x1, x2]))
    grad_f = gradient(x1, x2)
    n_grad = norm(grad_f)
    i +=1
    
evolution_X1 = evolution_X1_X2[:, 0]
evolution_X2 = evolution_X1_X2[:, 1]
x1 = np.linspace(2, 3.5, 150)
x2 = np.linspace(0.25, 1.75, 150)
X1, X2 = np.meshgrid(x1, x2)
Z = f(X1, X2)
fig = plt.figure(figsize = (10,7))
contours = plt.contour(X1, X2, Z, 20)
plt.clabel(contours, inline = True, fontsize = 10)
plt.title("Evolution of the cost function during gradient descent with level circles", fontsize=15)
plt.plot(evolution_X1, evolution_X2)
plt.plot(evolution_X1, evolution_X2, '*', label = "Cost function")
plt.xlabel('x1', fontsize=11)
plt.ylabel('x2', fontsize=11)
plt.colorbar()
## <matplotlib.colorbar.Colorbar object at 0x000000003F6F8520>
plt.legend(loc = "upper right")
plt.show()

# Referensi