Advertisement
Guest User

Untitled

a guest
Nov 14th, 2018
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.94 KB | None | 0 0
  1. # Transportation Problem
  2.  
  3. # Revised Simplex Method with Eta factorization
  4. import numpy as np
  5. import sys
  6. import copy
  7.  
  8.  
  9. class FileLogger(object):
  10.     def __init__(self, filename, mode):
  11.         self.terminal = sys.stdout
  12.         self.logfile = open(filename, mode)
  13.  
  14.     def write(self, message):
  15.         self.terminal.write(message)
  16.         self.logfile.write(message)
  17.  
  18.     def flush(self):
  19.         pass
  20.  
  21.  
  22. def start_logging_to_file(filename, mode):
  23.     sys.stdout = FileLogger(filename, mode)
  24.  
  25.  
  26. def stop_logging_to_file():
  27.     sys.stdout.logfile.close()
  28.     sys.stdout = sys.stdout.terminal
  29.  
  30.  
  31. class TP:
  32.     def __init__(self, num_storages, num_shops, a, b, matrix_c):
  33.         self.m = num_storages
  34.         self.n = num_shops
  35.         self.a = a
  36.         self.b = b
  37.         self.c = matrix_c
  38.         self.x = self.initial_solution()
  39.  
  40.     # Getting initial solution using minimum-cost method
  41.     # Trazenje pocetnog resenja metodom minimalnih cena
  42.     def initial_solution(self):
  43.         # If sum a_i is equal to sum b_i - closed transportation problem, otherwise introduce fictitious storage row
  44.         sum_a = np.sum(self.a)
  45.         sum_b = np.sum(self.b)
  46.         if sum_a < sum_b:
  47.             row_to_add = np.full((1, self.c.shape[1]), int(np.mean(self.c)) * 10)
  48.             self.c = np.r_[self.c, row_to_add]
  49.             self.a = np.append(self.a, [sum_b - sum_a])
  50.         elif sum_a > sum_b:
  51.             col_to_add = np.full((1, self.c.shape[0]), int(np.mean(self.c)) * 10)
  52.             self.c = np.c_[self.c, col_to_add.transpose()]
  53.             self.b = np.append(self.b, [sum_a - sum_b])
  54.  
  55.         # Indicator that shows whether the row/column should be considered when searching for min c_i,j
  56.         indicator = np.zeros(shape=(self.c.shape[0], self.c.shape[1]))
  57.         x = np.zeros(shape=(self.c.shape[0], self.c.shape[1]))
  58.  
  59.         a = copy.deepcopy(self.a)
  60.         b = copy.deepcopy(self.b)
  61.  
  62.         while True:
  63.             # Find row (p) and column (q) of the current available minimum element and assign new values to x, a, b
  64.             p = 0
  65.             q = 0
  66.             minimum_c = np.inf
  67.             for i in range(self.c.shape[0]):
  68.                 for j in range(self.c.shape[1]):
  69.                     if self.c[i][j] < minimum_c and indicator[i][j] == 0:
  70.                         p = i
  71.                         q = j
  72.                         minimum_c = self.c[p][q]
  73.  
  74.             min_ab = min(a[p], b[q])
  75.             x[p][q] = min_ab
  76.             a[p] -= min_ab
  77.             b[q] -= min_ab
  78.  
  79.             if a[p] == 0:
  80.                 indicator[p] = -1
  81.             else:
  82.                 indicator[:, q] = -1
  83.  
  84.             if a[p] == b[q]:
  85.                 break
  86.  
  87.         return x
  88.  
  89.     # Positions in the matrix are encoded with a number whose digits represent positions, a = ij (4: i = 0, j = 4)
  90.     def calculate_adjacency_list(self):
  91.         adj_list = {}
  92.         for i in range(self.x.shape[0]):
  93.             for j in range(self.x.shape[1]):
  94.                 if self.x[i][j] != 0:
  95.                     row_neighbours = [(i * 10 + k) for k in range(self.x.shape[1]) if self.x[i][k] != 0 and k != j]
  96.                     col_neighbours = [(k * 10 + j) for k in range(self.x.shape[0]) if self.x[k][j] != 0 and k != i]
  97.                     adj_list[i * 10 + j] = row_neighbours + col_neighbours
  98.  
  99.         return adj_list
  100.  
  101.     # Returns encoded values of positions where theta or theta negative should be added. Using DFS for cycle searching
  102.     @staticmethod
  103.     def find_theta_cycle(adj_list, marked, start):
  104.         path = [start]
  105.         marked[start] = True
  106.         while len(path) > 0:
  107.             v = path[-1]
  108.  
  109.             if v == start and len(path) > 3:
  110.                 return path
  111.  
  112.             has_unvisited = False
  113.  
  114.             for w in adj_list[v]:
  115.                 available = True
  116.                 # Disable stepping over already selected basic variable.
  117.                 wi = int(w / 10)
  118.                 wj = w % 10
  119.                 vi = int(v / 10)
  120.                 vj = v % 10
  121.                 for p in path:
  122.                     if p != v and p != w:
  123.                         pi = int(p / 10)
  124.                         pj = p % 10
  125.                         if ((vi == pi == wi and (vj < pj < wj or wj < pj < vj)) or
  126.                            (vj == pj == wj and (wi < pi < vi or vi < pi < wi))) and w not in marked:
  127.                             # print("v")
  128.                             # print(v)
  129.                             # print("p")
  130.                             # print(p)
  131.                             # print("w")
  132.                             # print(w)
  133.                             # print()
  134.                             available = False
  135.                 if len(path) > 1:
  136.                     p = path[-2]
  137.                     pi = int(p / 10)
  138.                     pj = p % 10
  139.                     if ((vi == pi == wi and (vj < wj < pj or pj < wj < vj)) or
  140.                        (vj == pj == wj and (pi < wi < vi or vi < wi < pi))) and w not in marked:
  141.                         available = False
  142.  
  143.                 if available and ((w == start and len(path) > 3 and len(path) % 2 == 0) or w not in marked):
  144.                     path.append(w)
  145.                     marked[w] = True
  146.                     has_unvisited = True
  147.                     break
  148.  
  149.             if not has_unvisited:
  150.                 path.pop()
  151.  
  152.         return []
  153.  
  154.     def method_of_potentials(self):
  155.         # Determining the row/column with maximum number of basic variables
  156.         i = 0
  157.         max_basic_i = 0
  158.         for k in range(self.x.shape[0]):
  159.             num_basic = np.count_nonzero(self.x[k] > 0)
  160.             if num_basic > max_basic_i:
  161.                 max_basic_i = num_basic
  162.                 i = k
  163.         j = 0
  164.         max_basic_j = 0
  165.         for k in range(self.x.shape[1]):
  166.             num_basic = np.count_nonzero(self.x[:, k] > 0)
  167.             if num_basic > max_basic_j:
  168.                 max_basic_j = num_basic
  169.                 j = k
  170.  
  171.         u = np.full((1, len(self.a)), np.inf)[0]
  172.         v = np.full((1, len(self.b)), np.inf)[0]
  173.  
  174.         # Setting that row/column of vector u/v to zero and calculating rest of u and v elements
  175.         if max_basic_i >= max_basic_j:
  176.             u[i] = 0
  177.         else:
  178.             v[j] = 0
  179.  
  180.         while np.any(u == np.inf) or np.any(v == np.inf):
  181.             for i in range(len(u)):
  182.                 if u[i] != np.inf:
  183.                     for j in range(len(v)):
  184.                         if self.x[i][j] != 0 and v[j] == np.inf:
  185.                             v[j] = self.c[i][j] - u[i]
  186.             for j in range(len(v)):
  187.                 if v[j] != np.inf:
  188.                     for i in range(len(u)):
  189.                         if self.x[i][j] != 0 and u[i] == np.inf:
  190.                             u[i] = self.c[i][j] - v[j]
  191.  
  192.         # Finding smallest value less than zero: c(non-basic)_i,j - (u_i + v_j).
  193.         # If all greater than or equal zero, optimal solution is found
  194.         neg_values = []
  195.         for i in range(self.c.shape[0]):
  196.             for j in range(self.c.shape[1]):
  197.                 if self.x[i][j] == 0:
  198.                     curr_diff = self.c[i][j] - (u[i] + v[j])
  199.                     if curr_diff < 0:
  200.                         neg_values.append((curr_diff, [i, j]))
  201.  
  202.         # Optimal solution found
  203.         if len(neg_values) == 0:
  204.             print("Optimal solution found!")
  205.             print(self.x)
  206.  
  207.         # Positioning theta on the smallest negative value. Creating cycle - start from theta position, go
  208.         # through basic variables and return at the starting position.
  209.         theta = np.zeros(shape=(self.c.shape[0], self.c.shape[1]))
  210.         pos_i = sorted(neg_values)[0][1][0]
  211.         pos_j = sorted(neg_values)[0][1][1]
  212.         # theta[pos_i][pos_j] = 1
  213.         self.x[pos_i][pos_j] = 1
  214.         adjacency_list = self.calculate_adjacency_list()
  215.         self.x[pos_i][pos_j] = 0
  216.  
  217.         print(adjacency_list)
  218.         marked = {}
  219.         start = pos_i * 10 + pos_j
  220.         positions = TP.find_theta_cycle(adjacency_list, marked, start)[:-1]
  221.         print(positions)
  222.         sign = -1
  223.         # Decode values and fill theta matrix
  224.         for pos in positions:
  225.             sign *= -1
  226.             i = int(pos / 10)
  227.             j = pos % 10
  228.             theta[i][j] = sign
  229.         theta[pos_i][pos_j] = 1
  230.         print(pos_i, pos_j)
  231.         # print(sorted(neg_values))
  232.         print(theta)
  233.  
  234.     def solve_problem(self):
  235.         print("Initial solution found using minimum-cost method: \n%s" % self.x)
  236.         # print("a")
  237.         # print(self.a)
  238.         # print("b")
  239.         # print(self.b)
  240.         # print("c")
  241.         # print(self.c)
  242.  
  243.         self.method_of_potentials()
  244.  
  245.  
  246. def main():
  247.     output_file = "output.txt"
  248.     mode = "a"
  249.     sys.stdout = FileLogger(output_file, mode)
  250.     ans = 'y'
  251.     while ans == 'y':
  252.         stop_logging_to_file()
  253.         # num_storages = int(input("Enter number of storages: "))
  254.         # num_shops = int(input("Enter number of shops: "))
  255.         #
  256.         # a = []
  257.         # print("Enter the a vector of length %s which contains quantity of merchandise in i-th storage: " % num_storages)
  258.         # a.append(list(map(float, input().rstrip().split())))
  259.         #
  260.         # b = []
  261.         # print("Enter the b vector of length %s which contains demand of j-th shop: " % num_shops)
  262.         # b.append(list(map(float, input().rstrip().split())))
  263.         #
  264.         # matrix_c = []
  265.         # print("Enter the %s x %s matrix C which contains transportation cost "
  266.         #       "from i-th storage to j-th shop: " % (num_storages, num_shops))
  267.         # for i in range(num_storages):
  268.         #     matrix_c.append(list(map(float, input().rstrip().split())))
  269.         # matrix_c = np.array(matrix_c)
  270.  
  271.         # print(num_storages)
  272.         # print(num_shops)
  273.         # print(a)
  274.         # print(b)
  275.         # print(matrix_c)
  276.         # print(matrix_x)
  277.  
  278.         # num_storages = 3
  279.         # num_shops = 4
  280.         # a = np.array([100, 200, 100])
  281.         # b = np.array([80, 120, 150, 50])
  282.         # matrix_c = np.array([[5, 4, 8, 3], [4, 7, 4, 5], [5, 3, 6, 1]])
  283.  
  284.         num_storages = 4
  285.         num_shops = 5
  286.         a = np.array([28, 13, 19, 18])
  287.         b = np.array([24, 16, 10, 20, 22])
  288.         # matrix_c = np.array([[1, 0, 0, 0, 0], [4, 2, 0, 1, 4], [4, 5, 6, 2, 0], [0, 0, 0, 1, 0]])
  289.         # matrix_c = np.array([[1, 0, 5, 6, 9], [4, 2, 7, 9, 4], [14, 25, 16, 21, 5], [3, 4, 2, 6, 1]])
  290.         # matrix_c = np.array([[1, 2, 3, 4, 5], [14, 12, 10, 11, 24], [34, 15, 6, 2, 7], [8, 8, 9, 1, 2]])
  291.         matrix_c = np.array([[3, 9, 8, 10, 4], [6, 10, 3, 2, 3], [3, 2, 7, 10, 3], [3, 2, 3, 2, 8]])
  292.  
  293.         problem = TP(num_storages, num_shops, a, b, matrix_c)
  294.         start_logging_to_file(output_file, mode)
  295.         problem.solve_problem()
  296.         stop_logging_to_file()
  297.         ans = input("Do you want to continue testing? (y/n) ")
  298.         start_logging_to_file(output_file, mode)
  299.  
  300.  
  301. if __name__ == '__main__':
  302.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement