diff --git a/resources/simplex/initialize.py b/resources/simplex/initialize.py new file mode 100644 index 0000000000000000000000000000000000000000..c2c7baa3a6a08684ae0515add23aab1abceca5c2 --- /dev/null +++ b/resources/simplex/initialize.py @@ -0,0 +1,108 @@ +""" +Date: 11-22-19 +Class: CS5310 +Assignment: Linear Programming Simplex Algorithm +Author: Brandon Rodriguez + + +Implementation of the "Initialize" function for Linear Programming Simplex problems. +""" + + +# System Imports. +import copy + +# User Class Imports. +from resources import logging as init_logging + + +# Initialize Logger. +logger = init_logging.get_logger(__name__) + + +class Initialize(): + def __init__(self, parent, *args, **kwargs): + # Get calling parent. We use this to pull parent data on __call__. + self._parent = parent + + # Parent data values to set later. + self._matrix_a = None + self._vector_b = None + self._vector_c = None + self._obj_constant_index = None + self._basic_var_indexes = None + self._nonbasic_var_indexes = None + + def __call__(self, *args, **kwargs): + # Get parent data at the point of call. + self._matrix_a = self._parent._matrix_a + self._vector_b = self._parent._constants + self._vector_c = self._parent._obj_func + self._obj_constant_index = self._parent._obj_constant_index + self._basic_var_indexes = self._parent._basic_var_indexes + self._nonbasic_var_indexes = self._parent._nonbasic_var_indexes + + # Run initialize function. + return self.initialize_simplex() + + def initialize_simplex(self): + # Determine smallest constant for constraints. + smallest_const_index = 0 + for index in range(len(self._vector_b)): + if self._vector_b[index] < self._vector_b[smallest_const_index]: + # Found a smaller value. Save index value. + smallest_const_index = index + + # Check if our smallest value is not negative. + if self._vector_b[smallest_const_index] >= 0: + # Smallest value is non-negative. Is feasible. + # We already know values so return as-is. + return ( + self._nonbasic_var_indexes, + self._basic_var_indexes, + self._matrix_a, + self._vector_b, + self._vector_c, + self._obj_constant_index, + ) + + # If we got this far, then one or more constraint constants are negative. + # This means we have an invalid simplex starting point, and want to correct it. + return self._correct_simplex(smallest_const_index) + + def _correct_simplex(self, smallest_index): + # Get values pulled from parent. We make sure we get a new copy and not a reference. + matrix_a = copy.deepcopy(self._matrix_a) + vector_b = copy.deepcopy(self._vector_b) + vector_c = copy.deepcopy(self._vector_c) + obj_const_index = self._obj_constant_index + b_array = copy.deepcopy(self._basic_var_indexes) + n_array = copy.deepcopy(self._nonbasic_var_indexes) + + # Add a "new" constraint variable. This will be set to 1 for all constants and -1 for obj func. + for row_index in range(len(matrix_a)): + matrix_a[row_index].append(1) + + # "Reset" objective function to 0 for everything other than our new var. + for col_index in range(len(vector_c)): + vector_c[col_index] = 0 + + # Add our new variable to the objective function as well. + vector_c.insert((len(vector_c) - 1), -1) + + # Update our parent values for a pivot. + self._parent._matrix_a = copy.deepcopy(matrix_a) + self._parent._obj_func = copy.deepcopy(vector_c) + self._parent._nonbasic_var_indexes.append(len(vector_c) - 2) + # logger.info('Nonbasics: {0}'.format(self._parent._nonbasic_var_indexes)) + # logger.info('Basics: {0}'.format(self._parent._basic_var_indexes)) + + # Now pivot once to get a feasible instance. + # self._parent.display_tableau() + # logger.info('Smallest Index: {0}'.format(smallest_index)) + self._parent.pivot(self._parent._basic_var_indexes[smallest_index], (len(vector_c) - 2)) + + # Need base "Simplex" function to run further? + return None + + diff --git a/resources/simplex/simplex.py b/resources/simplex/simplex.py index dc91d7f60d5fe40efa1e0b76a06dca04279cfafb..714a91417970e14f316109322af49e61274bad1d 100644 --- a/resources/simplex/simplex.py +++ b/resources/simplex/simplex.py @@ -36,6 +36,7 @@ Algorithm Variables (At least as far as I can tell): import json # User Class Imports. +from .initialize import Initialize from .pivot import Pivot from resources import logging as init_logging @@ -57,6 +58,7 @@ class Simplex(): self._nonbasic_var_indexes = None self._description = None + self._initialize = Initialize(self) self._pivot = Pivot(self) #region Simplex Read in and Setup @@ -394,6 +396,9 @@ class Simplex(): logger.info(' ' + '-' * tableau_length) logger.info('') + def initialize(self): + self._initialize() + def pivot(self, old_basic_index, new_basic_index): """ Pivots simplex around provided basic variable indexes. diff --git a/tests/resources/simplex/initialize.py b/tests/resources/simplex/initialize.py new file mode 100644 index 0000000000000000000000000000000000000000..4ff62ca5e807321fde7495a49fde2be1863676aa --- /dev/null +++ b/tests/resources/simplex/initialize.py @@ -0,0 +1,58 @@ +""" +Date: 11-22-19 +Class: CS5310 +Assignment: Linear Programming Simplex Algorithm +Author: Brandon Rodriguez + + +Tests for "Initialize" function implementation of the Simplex algorithm. +""" + +# System Imports. +import unittest + +# User Class Imports. +from resources.simplex.simplex import Simplex + + +class TestInitialize(unittest.TestCase): + def setUp(self): + self.simplex = Simplex() + + def test__initialize(self): + # Setup initial simplex. + self.simplex.set_simplex_values( + [ + [2, -1], + [1, -5], + ], + [2, -4], + [2, -1], + ) + # Test initial values after setup. + self.assertEqual(self.simplex._matrix_a, [ + [2, -1, 1, 0], + [1, -5, 0, 1], + ]) + self.assertEqual(self.simplex._constants, [2, -4]) + self.assertEqual(self.simplex._obj_func, [2, -1, 0, 0, 0]) + self.assertEqual(self.simplex._obj_constant_index, 4) + self.assertEqual(self.simplex._basic_var_indexes, [2, 3]) + self.assertEqual(self.simplex._nonbasic_var_indexes, [0, 1]) + + # Call initialize method to test. + # self.simplex.display_tableau() + self.simplex.initialize() + + # self.simplex.display_tableau() + + # # Test initial values "initialize" method. + # self.assertEqual(self.simplex._matrix_a, [ + # [1-5, 1, 0, 1/5], + # [-9/5, 0, 1, 1/5], + # ]) + # self.assertEqual(self.simplex._constants, [4/5, 14/5]) + # self.assertEqual(self.simplex._obj_func, [9/5, 0, 0, 1/5, -4/5]) + # self.assertEqual(self.simplex._obj_constant_index, 4) + # self.assertEqual(self.simplex._basic_var_indexes, [1, 2]) + # self.assertEqual(self.simplex._nonbasic_var_indexes, [0, 3])