Aleks11

OptimizeMethods

Dec 22nd, 2013
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.74 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <conio.h>
  3. #include <Windows.h>
  4.  
  5. #include <string>
  6. #include <vector>
  7. #include <algorithm>
  8. #include <cctype>
  9.  
  10. void RaiseError(std::string const &_sError)
  11. {
  12.     std::wstring sWError(_sError.begin(), _sError.end());
  13.     MessageBox(nullptr, sWError.c_str(), L"Error", MB_OK);
  14. }
  15.  
  16. void RaiseError(std::wstring const &_sWError)
  17. {
  18.     MessageBox(nullptr, _sWError.c_str(), L"Error", MB_OK);
  19. }
  20.  
  21. #define RAISE_ERROR(str) \
  22.     RaiseError(str); \
  23.     _getch(); \
  24.     return 0;
  25.  
  26. void ToLower(std::string &s)
  27. {
  28.     for (char &c : s)
  29.     {
  30.         c = std::tolower(c);
  31.     }
  32. }
  33.  
  34. enum class eSolutionState
  35. {
  36.     INITIALIZED = 0,
  37.     FIRSTSTEP,
  38.     SECONDSTEP,
  39.     FINISHED,
  40.     FAILED
  41. } g_eSolutionState(eSolutionState::INITIALIZED);
  42.  
  43. class CSimplexTable
  44. {
  45. public:
  46.     // заголовки строк и столбцов
  47.     std::vector<size_t> m_RowHeaders; // доп. переменные(базисные)
  48.     std::vector<size_t> m_ColumnHeaders; // исходные переменные(небазисные)
  49.  
  50.     // данные(целевая функция в первой строке, свободные члены в первом столбце)
  51.     std::vector<std::vector<float>> m_Table;
  52.  
  53.     bool m_bIsMin;
  54. };
  55.  
  56. CSimplexTable g_STable;
  57.  
  58. void PrintTable()
  59. {
  60.     printf("\t%s\t", "Free");
  61.  
  62.     for (size_t i = 0; i < g_STable.m_ColumnHeaders.size(); i++)
  63.     {
  64.         printf("x%d\t", g_STable.m_ColumnHeaders[i] + 1);
  65.     }
  66.  
  67.     printf("\n %s\t", "F");
  68.  
  69.     for (size_t i = 0; i < g_STable.m_ColumnHeaders.size() + 1; i++)
  70.     {
  71.         printf("%0.3f\t", g_STable.m_Table[0][i]);
  72.     }
  73.  
  74.     for (size_t i = 0; i < g_STable.m_RowHeaders.size(); i++)
  75.     {
  76.         printf("\n X%d \t", g_STable.m_RowHeaders[i] + 1);
  77.  
  78.         for (size_t j = 0; j < g_STable.m_ColumnHeaders.size() + 1; j++)
  79.         {
  80.             printf("%0.3f\t", g_STable.m_Table[i + 1][j]);
  81.         }
  82.     }
  83.  
  84.     printf("\n\n");
  85. }
  86.  
  87. bool ParseInputToTable(std::string const &_sFunc, std::string const _Equations[], size_t _nEquationCount)
  88. {
  89.     // ошибка всплывает только при парсинге(коряво написанные функция или уравнения)
  90.  
  91.     auto _ParseConstAndVar = [](std::string &_sDest, float &fConst, char &cVar, size_t &nVar)
  92.     {
  93.         sscanf(_sDest.c_str(), "%f%c%d", &fConst, &cVar, &nVar);
  94.  
  95.         // стираем строчку
  96.         char sFind[20];
  97.         int nFindLen = sprintf_s(sFind, 20, "%c%d", cVar, nVar);
  98.         _sDest.erase(_sDest.begin(), _sDest.begin() + _sDest.find(sFind) + nFindLen);
  99.     };
  100.  
  101.     // место для целевой функции
  102.     g_STable.m_Table.push_back(std::vector<float>());
  103.  
  104.     size_t nMaxVarNumber = 0;
  105.  
  106.     // парсим уравнения:
  107.     for (size_t iEq = 0; iEq < _nEquationCount; iEq++)
  108.     {
  109.         std::string sEq = _Equations[iEq];
  110.  
  111.         ToLower(sEq);
  112.  
  113.         if (sEq.size() < 3)
  114.             return false;
  115.  
  116.         // 2. нужно убрать конец(знак отношения и число)
  117.         size_t found = sEq.find_first_of("<>=");
  118.  
  119.         if (found == sEq.npos)
  120.             return false;
  121.  
  122.         char sOperator[20];
  123.         float fFreeConst;
  124.  
  125.         bool bNegate = false;
  126.        
  127.         if (sscanf((sEq.substr(found, sEq.size() - found)).c_str(), "%s %f", sOperator, &fFreeConst) < 2)
  128.             return false;
  129.        
  130.         sEq.erase(sEq.begin() + found, sEq.end());
  131.  
  132.         // если оператор >= или >, то меняем знаки
  133.         if (std::string(sOperator).find_first_of(">") != std::string(sOperator).npos)
  134.         {
  135.             bNegate = true;
  136.  
  137.             fFreeConst = -fFreeConst;
  138.         }
  139.  
  140.         sEq.erase(std::remove_if(sEq.begin(), sEq.end(),
  141.             [](char c) { return (c =='\r' || c =='\t' || c == ' ' || c == '*' || c == '\n'); }), sEq.end());
  142.  
  143.         g_STable.m_Table.push_back(std::vector<float>());
  144.         g_STable.m_Table.back().push_back(fFreeConst);
  145.  
  146.         while (!sEq.empty())
  147.         {
  148.             float fConst;
  149.             char cVar;
  150.             size_t nVar;
  151.  
  152.             _ParseConstAndVar(sEq, fConst, cVar, nVar);
  153.  
  154.             if (nMaxVarNumber < nVar)
  155.                 nMaxVarNumber = nVar;
  156.  
  157.             if (bNegate)
  158.                 fConst = -fConst;
  159.  
  160.             // добавляем нолики, если пропущены переменные(x1...x3, добавим x2)
  161.             for (int i = (int)g_STable.m_Table.back().size() - 1; i < (int)nVar - 2; i++)
  162.                 g_STable.m_Table.back().push_back(0.0f);
  163.  
  164.             g_STable.m_Table.back().push_back(fConst);
  165.         }
  166.     }
  167.  
  168.     // ------------------------------------------------------------------------------------------------
  169.  
  170.     {
  171.         // парсим функцию:
  172.         std::string sModifiedFunc = _sFunc;
  173.         ToLower(sModifiedFunc);
  174.  
  175.         // 1. убираем все пробелы и всякие знаки сброса каретки и т.д. + знак умножения
  176.         sModifiedFunc.erase(std::remove_if(sModifiedFunc.begin(), sModifiedFunc.end(),
  177.             //[](char c) { return (!isdigit(c) && !isalpha(c) && c != '+' && c != '-' && c != '>'); }), sModifiedFunc.end());
  178.             [](char c) { return (c =='\r' || c =='\t' || c == ' ' || c == '*' || c == '\n'); }), sModifiedFunc.end());
  179.  
  180.         if (sModifiedFunc.size() < 3)
  181.             return false;
  182.  
  183.         // 2. определяем какая функция: минимум или максимум
  184.         std::string sMinOrMax = sModifiedFunc.substr(sModifiedFunc.size() - 3, 3);
  185.         if (sMinOrMax == "min")
  186.             g_STable.m_bIsMin = true;
  187.         else if (sMinOrMax == "max")
  188.             g_STable.m_bIsMin = false;
  189.         else
  190.             return false;
  191.  
  192.         size_t nPos = sModifiedFunc.find("->");
  193.         if (nPos == sModifiedFunc.npos)
  194.             return false;
  195.  
  196.         sModifiedFunc.erase(sModifiedFunc.begin() + nPos, sModifiedFunc.end());
  197.  
  198.         // 3. парсим все иксы и константы к ним
  199.  
  200.         g_STable.m_Table[0].push_back(0.0f);
  201.  
  202.         while (!sModifiedFunc.empty())
  203.         {
  204.             float fConst;
  205.             char cVar;
  206.             size_t nVar;
  207.  
  208.             _ParseConstAndVar(sModifiedFunc, fConst, cVar, nVar);
  209.  
  210.             if (!g_STable.m_bIsMin)
  211.             {
  212.                 // по идее надо...
  213.                 fConst = -fConst;
  214.             }
  215.  
  216.             // добавляем нолики, если пропущены переменные(x1...x3, добавим x2)
  217.             for (int i = (int)g_STable.m_Table[0].size() - 1; i < (int)nVar - 2; i++)
  218.                 g_STable.m_Table[0].push_back(0.0f);
  219.  
  220.             // и добавляем новую
  221.             g_STable.m_Table[0].push_back(fConst);
  222.         }
  223.     }
  224.  
  225.     // добавляем недостающие коэффициенты
  226.     for (auto &iVector : g_STable.m_Table)
  227.     {
  228.         while (iVector.size() <= nMaxVarNumber)
  229.         {
  230.             iVector.push_back(0.0f);
  231.         }
  232.     }
  233.  
  234.     // теперь заполняем заголовки(по дефолту)
  235.     for (size_t i = 0; i < nMaxVarNumber; i++)
  236.         g_STable.m_ColumnHeaders.push_back(i);
  237.  
  238.     for (size_t i = 0; i < _nEquationCount; i++)
  239.         g_STable.m_RowHeaders.push_back(nMaxVarNumber + i);
  240.  
  241.     // выведем результат парсинга и первичной подготовки:
  242.     PrintTable();
  243.  
  244.     g_eSolutionState = eSolutionState::INITIALIZED;
  245.  
  246.     return true;
  247. }
  248.  
  249. void RecomputeTable(size_t iLeadingRow, size_t iLeadingCol)
  250. {
  251.     // меняем местами
  252.     int nTemp = g_STable.m_RowHeaders[iLeadingRow - 1];
  253.     g_STable.m_RowHeaders[iLeadingRow - 1] = g_STable.m_ColumnHeaders[iLeadingCol - 1];
  254.     g_STable.m_ColumnHeaders[iLeadingCol - 1] = nTemp;
  255.  
  256.     // и преобразуем таблицу
  257.     std::vector<float> CopyLeadingRow(g_STable.m_ColumnHeaders.size() + 1);
  258.     std::vector<float> CopyLeadingCol(g_STable.m_RowHeaders.size() + 1);
  259.  
  260.     float fLeadingValue = 1 / g_STable.m_Table[iLeadingRow][iLeadingCol];
  261.  
  262.     // проход по столбцу
  263.     for (size_t i = 0; i < g_STable.m_RowHeaders.size() + 1; i++)
  264.     {
  265.         CopyLeadingCol[i] = g_STable.m_Table[i][iLeadingCol];
  266.  
  267.         if (i == iLeadingRow)
  268.             continue;
  269.  
  270.         g_STable.m_Table[i][iLeadingCol] *= -fLeadingValue;
  271.     }
  272.  
  273.     // проход по строке
  274.     for (size_t i = 0; i < g_STable.m_ColumnHeaders.size() + 1; i++)
  275.     {
  276.         CopyLeadingRow[i] = g_STable.m_Table[iLeadingRow][i];
  277.  
  278.         if (i == iLeadingCol)
  279.             continue;
  280.  
  281.         g_STable.m_Table[iLeadingRow][i] *= fLeadingValue;
  282.     }
  283.  
  284.     g_STable.m_Table[iLeadingRow][iLeadingCol] = 1 / g_STable.m_Table[iLeadingRow][iLeadingCol];
  285.  
  286.     // проход по строкам
  287.     for (size_t i = 0; i < g_STable.m_RowHeaders.size() + 1; i++)
  288.     {
  289.         if (i == iLeadingRow)
  290.             continue;
  291.  
  292.         // проход по столбцам
  293.         for (size_t j = 0; j < g_STable.m_ColumnHeaders.size() + 1; j++)
  294.         {
  295.             if (j == iLeadingCol)
  296.                 continue;
  297.  
  298.             g_STable.m_Table[i][j] = g_STable.m_Table[i][j] - (CopyLeadingCol[i] * CopyLeadingRow[j]) * fLeadingValue;
  299.         }
  300.     }
  301. }
  302.  
  303. void FirstIterateTable()
  304. {
  305.     // если все свободные - позитивны, то к шагу два переходим
  306.     bool bIsAllPositive = true;
  307.  
  308.     for (size_t i = 1; i < g_STable.m_RowHeaders.size() + 1; i++)
  309.     {
  310.         if (g_STable.m_Table[i][0] < 0.0f)
  311.         {
  312.             bIsAllPositive = false;
  313.             break;
  314.         }
  315.     }
  316.  
  317.     if (bIsAllPositive)
  318.     {
  319.         g_eSolutionState = eSolutionState::SECONDSTEP;
  320.         return;
  321.     }
  322.  
  323.     // если нет, то надо выбрать самый минимальный в свободном, это будет ведущая строчка
  324.     size_t iLeadingRow = -1;
  325.     for (size_t i = 1; i < g_STable.m_RowHeaders.size() + 1; i++)
  326.     {
  327.         if (iLeadingRow == -1 || g_STable.m_Table[i][0] < g_STable.m_Table[iLeadingRow][0])
  328.         {
  329.             iLeadingRow = i;
  330.         }
  331.     }
  332.  
  333.     // выбираем ведущий столбец, как самый минимальный в ведущей строчке
  334.     size_t iLeadingCol = -1;
  335.     for (size_t i = 1; i < g_STable.m_ColumnHeaders.size() + 1; i++)
  336.     {
  337.         if ((iLeadingCol == -1 || g_STable.m_Table[iLeadingRow][i] < g_STable.m_Table[iLeadingRow][iLeadingCol]) &&
  338.             g_STable.m_Table[iLeadingRow][i] < 0.0f)
  339.         {
  340.             iLeadingCol = i;
  341.         }
  342.     }
  343.  
  344.     if (iLeadingCol == -1)
  345.     {
  346.         g_eSolutionState = eSolutionState::FAILED;
  347.         return;
  348.     }
  349.  
  350.     RecomputeTable(iLeadingRow, iLeadingCol);
  351.  
  352.     PrintTable();
  353. }
  354.  
  355. void SecondIterateTable()
  356. {
  357.     bool bIsAllPositive = true;
  358.  
  359.     for (size_t i = 1; i < g_STable.m_ColumnHeaders.size() + 1; i++)
  360.     {
  361.         if (g_STable.m_Table[0][i] < 0.0f)
  362.         {
  363.             bIsAllPositive = false;
  364.             break;
  365.         }
  366.     }
  367.  
  368.     // нет отрицательных - найдено оптимальное решение
  369.     if (bIsAllPositive)
  370.     {
  371.         g_eSolutionState = eSolutionState::FINISHED;
  372.         return;
  373.     }
  374.  
  375.     // если есть, то надо улучшать
  376.     size_t iLeadingCol = -1;
  377.     for (size_t i = 1; i < g_STable.m_ColumnHeaders.size() + 1; i++)
  378.     {
  379.         if (iLeadingCol == -1 || g_STable.m_Table[0][i] < g_STable.m_Table[0][iLeadingCol])
  380.         {
  381.             iLeadingCol = i;
  382.         }
  383.     }
  384.  
  385.     size_t iLeadingRow = -1;
  386.     for (size_t i = 1; i < g_STable.m_RowHeaders.size() + 1; i++)
  387.     {
  388.         if ((iLeadingRow == -1 ||
  389.             g_STable.m_Table[i][0] / g_STable.m_Table[i][iLeadingCol] < g_STable.m_Table[iLeadingRow][0] / g_STable.m_Table[iLeadingRow][iLeadingCol]) &&
  390.             g_STable.m_Table[i][0] >= 0.0f && g_STable.m_Table[i][iLeadingCol] >= 0.0f)
  391.         {
  392.             iLeadingRow = i;
  393.         }
  394.     }
  395.  
  396.     if (iLeadingRow == -1)
  397.     {
  398.         g_eSolutionState = eSolutionState::FAILED;
  399.         return;
  400.     }
  401.  
  402.     RecomputeTable(iLeadingRow, iLeadingCol);
  403.  
  404.     PrintTable();
  405. }
  406.  
  407. void PrintResult()
  408. {
  409.     float fResult = g_STable.m_Table[0][0];
  410.     if (g_STable.m_bIsMin)
  411.         fResult = -fResult;
  412.  
  413.     printf("F = %0.3f\n\n", fResult);
  414.  
  415.     // здесь надо взять m_ColumnHeaders.size() переменных первых, но только тех, которые в m_RowHeaders
  416.     std::vector<float> Variables(g_STable.m_ColumnHeaders.size(), 0.0f);
  417.  
  418.     for (size_t i = 0; i < g_STable.m_RowHeaders.size(); i++)
  419.     {
  420.         if (g_STable.m_RowHeaders[i] < g_STable.m_ColumnHeaders.size())
  421.         Variables[g_STable.m_RowHeaders[i]] = g_STable.m_Table[i + 1][0];
  422.     }
  423.  
  424.     int iCountVar = 0;
  425.     for (float const iVar : Variables)
  426.     {
  427.         printf("x%d = %0.3f\n", iCountVar + 1, iVar);
  428.  
  429.         iCountVar++;
  430.     }
  431. }
  432.  
  433. int main()
  434. {
  435.     // на вход подаётся функция и какое-то количество условий ограничивающих
  436.  
  437.     // Целевая функция:
  438.     std::string sFunc = "1 * x1 + 1 * x2 + 1 * x3 + 1 * x4 + 1 * x5 + 1 * x6 + 1 * x7 + 1 * x8 + 1 * x9 + 1 * x10 + 1 * x11 + 1 * x12 + 1 * x13 + 1 * x14 + 1 * x15 -> max";
  439.  
  440.     // теперь на вход подаются условия:
  441.     std::string sEquations[] =
  442.     {
  443.         "0.3    x1 + 0.25   x2 + 0.2    x3 + 0.166  x4 + 0.143  x5 + 0.125  x6 + 0.111  x7 + 0.1    x8 + 0.09   x9 + 0.083  x10 + 0.077     x11 + 0.0714    x12 + 0.0666    x13 + 0.0625    x14 + 0.0588 x15 = 14",
  444.         "0.25   x1 + 0.2    x2 + 0.166  x3 + 0.143  x4 + 0.125  x5 + 0.111  x6 + 0.1    x7 + 0.09   x8 + 0.083  x9 + 0.077  x10 + 0.0714    x11 + 0.0666    x12 + 0.0625    x13 + 0.0588    x14 + 0.0555 x15 = 13",
  445.         "0.2    x1 + 0.166  x2 + 0.143  x3 + 0.125  x4 + 0.111  x5 + 0.1    x6 + 0.09   x7 + 0.083  x8 + 0.077  x9 + 0.0714 x10 + 0.0666    x11 + 0.0625    x12 + 0.0588    x13 + 0.0555    x14 + 0.0526 x15 = 12",
  446.         "0.166  x1 + 0.143  x2 + 0.125  x3 + 0.111  x4 + 0.1    x5 + 0.09   x6 + 0.083  x7 + 0.077  x8 + 0.0714 x9 + 0.0666 x10 + 0.0625    x11 + 0.0588    x12 + 0.0555    x13 + 0.0526    x14 + 0.05   x15 = 11",
  447.         "0.143  x1 + 0.125  x2 + 0.111  x3 + 0.1    x4 + 0.09   x5 + 0.083  x6 + 0.077  x7 + 0.0714 x8 + 0.0666 x9 + 0.0625 x10 + 0.0588    x11 + 0.0555    x12 + 0.0526    x13 + 0.05      x14 + 0.0476 x15 = 10"
  448.     };
  449.  
  450.     /*
  451.     // Целевая функция:
  452.     std::string sFunc = "2 * x1 + 5 * x2 + 3 * x3 + 8 * x4 -> min";
  453.  
  454.     // теперь на вход подаются условия:
  455.     std::string sEquations[] =
  456.     {
  457.         "3 * x1 + 6 * x2 - 4 * x3 + 1 * x4 <= 12",
  458.         "4 * x1 - 13 * x2 + 10 * x3 + 5 * x4 >= 6",
  459.         "3 * x1 + 7 * x2 + 1 * x3 >= 1"
  460.     };
  461.     */
  462.  
  463.     // теперь надо их распарсить в табличку
  464.     if (!ParseInputToTable(sFunc, sEquations, ARRAYSIZE(sEquations)))
  465.     {
  466.         RAISE_ERROR("Parse error!");
  467.     }
  468.  
  469.     while (g_eSolutionState != eSolutionState::FINISHED)
  470.     {
  471.         if (g_eSolutionState != eSolutionState::SECONDSTEP)
  472.         {
  473.             FirstIterateTable();
  474.         }
  475.         else
  476.         {
  477.             SecondIterateTable();
  478.         }
  479.  
  480.         if (g_eSolutionState == eSolutionState::FAILED)
  481.         {
  482.             RAISE_ERROR("It is not possible to solve!");
  483.         }
  484.     }
  485.  
  486.     // state = finished
  487.     PrintResult();
  488.  
  489.     _getch();
  490.     return 0;
  491. };
Advertisement
Add Comment
Please, Sign In to add comment