LinearProblem.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Security.Cryptography.X509Certificates;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace MathMod
  8. {
  9. //универсальные методы решения задач линейной математики
  10. internal class LinearProblem
  11. {
  12. public enum problemType { min, max }
  13. List<List<double>> restrictions_;
  14. List<double> free_variables_;
  15. List<double> objective_fun_;
  16. readonly List<double> values_in_result_;
  17. double objective_fun_value;
  18. problemType type_;
  19. List<int> basis_indexes_;
  20. List<string> comparison_signs_;
  21. void ReduceToCanonicalForm()
  22. {
  23. int balance_variable_count = restrictions_.Count;
  24. for (int i = 0; i < balance_variable_count; i++)
  25. {
  26. if (comparison_signs_[i] == ">=" || comparison_signs_[i] == "<=")
  27. {
  28. for (int j = 0; j < balance_variable_count; j++)
  29. restrictions_[i].Add(0);
  30. if (comparison_signs_[i] == "<=" || comparison_signs_[i] == ">=")
  31. {
  32. int basis_ind = objective_fun_.Count + i;
  33. restrictions_[i][basis_ind] = 1;
  34. if (comparison_signs_[i] == ">=")
  35. {
  36. restrictions_[i][basis_ind] = -1;
  37. restrictions_[i] = restrictions_[i].Select(x => -x).ToList();
  38. free_variables_[i] *= -1;
  39. }
  40. }
  41. }
  42. else if (comparison_signs_[i] == "=") continue;
  43. else throw new FormatException($"Ожидаются символы: >=, <=, =. Фактический: {comparison_signs_[i]}");
  44. }
  45. for (int j = 0; j < balance_variable_count; j++)
  46. objective_fun_.Add(0);
  47. }
  48. List<int> PickOutBasis()
  49. {
  50. List<int> basis = new List<int>();
  51. for (int j = 0; j < restrictions_[0].Count; ++j)
  52. {
  53. bool onlyCanonicalSigns = true;
  54. int ones = 0;
  55. for (int i = 0; i < restrictions_.Count; ++i)
  56. {
  57. if (restrictions_[i][j] != 0 && restrictions_[i][j] != 1)
  58. {
  59. onlyCanonicalSigns = false;
  60. break;
  61. }
  62. if (restrictions_[i][j] == 1) ++ones;
  63. }
  64. if (onlyCanonicalSigns && ones == 1) basis.Add(j);
  65. }
  66. if (basis.Count != restrictions_.Count) throw new ArgumentException($"Ожидаемая размерность базиса {restrictions_.Count}. Фактическая: {basis.Count}");
  67. return basis;
  68. }
  69. public LinearProblem(List<List<double>> a, List<string> comparison_signs, List<double> b, List<double> c, problemType type)
  70. {
  71. restrictions_ = a;
  72. comparison_signs_ = comparison_signs;
  73. free_variables_ = b;
  74. objective_fun_ = c.Select(x => -x).ToList();
  75. values_in_result_ = new List<double> { };
  76. for (int i = 0; i < objective_fun_.Count; ++i) if (objective_fun_[i] != 0) values_in_result_.Add(i);
  77. type_ = type;
  78. ReduceToCanonicalForm();
  79. basis_indexes_ = PickOutBasis();
  80. }
  81. //возвращает -1, если в базис вводить нечего, иначе индекс вводимой переменной
  82. int EnteringIntoBasis()
  83. {
  84. if (type_ == problemType.min)
  85. return objective_fun_.FindIndex(x => x == objective_fun_.Max() && x > 0);
  86. else//type_ == problemType.max
  87. return objective_fun_.FindIndex(x => x == objective_fun_.Min() && x < 0);
  88. }
  89. int DerivationFromBasis(int leading_col)
  90. {
  91. List<double> divided_right_side = free_variables_.Select(x => x).ToList();
  92. for (int i = 0; i < divided_right_side.Count; ++i)
  93. {
  94. if (restrictions_[i][leading_col] <= 0) divided_right_side[i] = 0;
  95. else divided_right_side[i] /= restrictions_[i][leading_col];
  96. }
  97. return divided_right_side.FindIndex(x => x == divided_right_side.FindAll(x => x > 0).Min());
  98. }
  99. public void SimplexMethod()
  100. {
  101. bool is_optimal = false;
  102. while (!is_optimal)
  103. {
  104. int leading_col = EnteringIntoBasis();
  105. if (leading_col == -1)
  106. {
  107. is_optimal = true;
  108. break;
  109. }
  110. int leading_row = DerivationFromBasis(leading_col);
  111. double leading_elem = restrictions_[leading_row][leading_col];
  112. basis_indexes_[leading_row] = leading_col;
  113. for (int j = 0; j < restrictions_[0].Count; ++j)
  114. restrictions_[leading_row][j] /= leading_elem;
  115. free_variables_[leading_row] /= leading_elem;
  116. double divider;
  117. for (int i = 0; i < restrictions_.Count; ++i)
  118. {
  119. if (i == leading_row) continue;
  120. divider = -restrictions_[i][leading_col];
  121. for (int j = 0; j < restrictions_[0].Count; ++j)
  122. restrictions_[i][j] += divider * restrictions_[leading_row][j];
  123. free_variables_[i] += divider * free_variables_[leading_row];
  124. }
  125. divider = -objective_fun_[leading_col];
  126. for (int j = 0; j < restrictions_[0].Count; ++j)
  127. objective_fun_[j] += divider * restrictions_[leading_row][j];
  128. objective_fun_value += divider * free_variables_[leading_row];
  129. }
  130. }
  131. public string GetObjectiveFun()
  132. {
  133. string text_func = "";
  134. for (int i = 0; i < basis_indexes_.Count; ++i)
  135. if (-1 != values_in_result_.FindIndex(x => x == basis_indexes_[i]))
  136. text_func += $"x{basis_indexes_[i] + 1}={Math.Round(free_variables_[i], 3)} ";
  137. text_func += $"\nL(x)={Math.Round(objective_fun_value, 3)}";
  138. return text_func;
  139. }
  140. }
  141. }