"""
Created on Tue Jun 21 14:11:29 2016
@author: Bossa
Algoritmo 6.3.2: Primal-Dual Path Following
Powered by Spider 2
"""
import numpy as np
np.set_printoptions(precision=3)
class PrimalDualPF():
'''
Implementação do método Primal Dual Path Following para o problema
de programação linear
min c*x
s.a. Ax = b
x >= 0
Parâmetros
----------
A: matriz mxn com as variáveis de folga já inseridas.
b: vetor nx1
c: vetor de custo mx1
x: solução inicial do problema primal
w: solução inicial do problema dual
s: folga dual associada a solução w
'''
def __init__(self, A, b, c, x, w, s):
self.A = np.array(A)
self.b = np.array(b)
self.c = np.zeros_like(A[0])
self.c[0:len(c)] = np.array(c)
self.x = np.array(x)
self.w = np.array(w)
self.s = np.array(s)
(m,n) = self.A.shape
self.mu = np.dot(self.x,self.s)/n
self.gamma = 1e-3
def update(self):
(m,n) = self.A.shape
self.mu = np.dot(self.x,self.s)/n
J1 = np.concatenate(
(np.zeros((n,n)), np.transpose(self.A), np.eye(n)),axis=1)
J2 = np.concatenate(
(self.A, np.zeros((m,m)), np.zeros((m,n))),axis=1)
J3 = np.concatenate(
(np.diag(self.s), np.zeros((n,m)), np.diag(self.x)),axis=1)
self.jacobian = np.concatenate((J1,J2,J3))
D1 = self.c - self.A.T.dot(self.w) - self.s
D2 = self.b - self.A.dot(self.x)
D3 = -1*np.multiply(self.s,self.x)*np.ones(n) + \
self.sigma*self.mu*np.ones(n)
self.RHS = np.concatenate((D1,D2,D3))
def step(self):
(m,n) = self.A.shape
solucao = np.linalg.solve(self.jacobian,self.RHS)
px = solucao[0:n]
pw = solucao[n:m+n]
ps = solucao[m+n:m+2*n]
alpha = 1.0
backtracking = True
while backtracking:
novox = self.x + alpha*px
novow = self.w + alpha*pw
novos = self.s + alpha*ps
const = self.gamma*self.mu
if validacao(novox,const) and validacao(novos,const):
backtracking = False
else:
alpha = 0.9*alpha
self.x = novox
self.w = novow
self.s = novos
def solve(self, TOL=1e-3,MAXSTEPS=1000, SIGMA=.2):
'''Itera os passos de resolução até que a precisão TOL seja alcançada'''
self.sigma = SIGMA
self.caminho = [[],[]]
for k in range(MAXSTEPS):
if self.mu < TOL:
break
else:
for j in range(2):
self.caminho[j].append(self.x[j])
self.update()
self.step()
def solution(self):
return (self.x,self.w,self.s)
def validacao(vector,constante):
'''Verifica se cada entrada de um dado vetor é maior que a constante.'''
test = True
for x in vector:
if x <= constante:
test = False
break
return test