linear-system.lisp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. "Важный момент:
  2. В виде списков чисел представлены три сущности:
  3. 1) Уравнения.
  4. Записаны как список коэфициентов при неизвестных.
  5. Равны нулю
  6. 2) Выражения.
  7. Записаны как список коэфициентов при неизвестный.
  8. Равны следующму неизвестному
  9. 3) Список значений неизвесных.
  10. В нём самой правой идёт единица - так сказать, неизвестное при свободном
  11. коэфициенте. Левее, следующий коэфициент.
  12. То, какое число к какому неизвестному относится зависит только от его положения
  13. в списке."
  14. (defun list-mul (list num)
  15. "Умножаем все элементы списка на число"
  16. (if (null list)
  17. nil
  18. (cons (* (car list)
  19. num)
  20. (list-mul (cdr list)
  21. num))))
  22. (defun list-div (list num)
  23. "Делит все числа в списке на число"
  24. (list-mul list
  25. (/ 1 num)))
  26. (defun list-sum (list-a list-b)
  27. "Складывает все "
  28. (mapcar '+
  29. list-a
  30. list-b))
  31. (defun express-left-unknown (eqtn)
  32. "Выражает самое левое неизвестное через все остальные
  33. На выходе получается список чисел. Он похож на запись уравнения,
  34. но равен не нулю, а самому левому неизвестному"
  35. (list-div (cdr eqtn)
  36. (- (car eqtn))))
  37. (defun replace-left-unknown (eqtn expr)
  38. "Принимает уравнение, выражение, которое выражает первую переменную на все
  39. остальные, и заменяет первую переменную на это выражение)"
  40. (list-sum (cdr eqtn)
  41. (list-mul expr
  42. (car eqtn))))
  43. (defun replace-in-system (system expr)
  44. "Заменяет самую левую переменную во всей системе"
  45. (if (null system)
  46. nil
  47. (cons (replace-left-unknown (car system)
  48. expr)
  49. (replace-in-system (cdr system)
  50. expr))))
  51. (defun zero-eqtn? (eqtn)
  52. "Проверяет, что все числа в уравнении равны нулю"
  53. (apply '= 0 eqtn))
  54. (defun inconsistent? (eqtn)
  55. "Проверяет, что в уравнении есть только один свободный
  56. коэфициент, и он не равен нулю. Так как само уравнение должно быть равно нулю, это значит, что мы нашли противоречие."
  57. (cond ((null eqtn)
  58. nil)
  59. ((and (null (cdr eqtn))
  60. (/= (car eqtn)
  61. 0))
  62. t)
  63. ((= (car eqtn)
  64. 0)
  65. (inconsistent? (cdr eqtn)))
  66. (t
  67. nil)))
  68. (defun forward (system expressions)
  69. "Принимаем систему уравнений, и проходимся по ней вперёд.
  70. Выражаем левое неизвестное первого выражения через все остальные
  71. и заменяем эту переменную на выражение во всех остальных уравнениях системы.
  72. Выражения запоминаем в список expressions.
  73. В результате, всё сокращается на одно неизвестное. Продолжаем до тех пор, пока
  74. не кончатся все уравнения, либо пока не придём к противоречию.
  75. Если уравнения кончатся, мы отдаём список выражений."
  76. (cond ((null system)
  77. expressions)
  78. ((zero-eqtn? (car system))
  79. (forward (cdr system)
  80. expressions))
  81. ((inconsistent? (car system))
  82. (print "ОШИБКА! Система противоречива"))
  83. (t
  84. (let* ((eqtn (car system))
  85. (expr (express-left-unknown eqtn)))
  86. (forward (replace-in-system (cdr system)
  87. expr)
  88. (cons expr
  89. expressions))))))
  90. (defun subst-vals (expr values)
  91. "Функция подставляет значения неизвестных в выражение, чтобы получить
  92. следующее неивестное. Для этого он перемножает значения неизвестных на
  93. коэфициенты при них (коэфициенты находятся в выражении)."
  94. (apply '+ (mapcar '*
  95. expr
  96. values)))
  97. (defun go-back (exprs values-of-unknowns)
  98. (if (null exprs)
  99. values-of-unknowns
  100. (go-back (cdr exprs)
  101. (cons (subst-vals (car exprs)
  102. values-of-unknowns)
  103. values-of-unknowns))))
  104. (defun backward (expressions)
  105. "Получает список всех выражений, которые получились в результате
  106. решения системы. Если последнее выражение содержит в себе только один коэфициент,
  107. это значит, что это коэфициент при единице. Значит, система имеет решение.
  108. Если в послежнем выражении несколько коэфициентов, значит, в системе бесконечно много
  109. решений"
  110. (cond ((> (length (car expressions))
  111. 1)
  112. (cons 'infinity
  113. expressions))
  114. (t
  115. (cons 'values-of-unknowns
  116. (go-back expressions
  117. '(1))))))
  118. (defun parse-equation (eq)
  119. (let ((coeffs (make-hash-table :test #'equal))
  120. (free 0)
  121. (current-coeff 1))
  122. (dolist (term eq)
  123. (cond
  124. ((eq term '=)
  125. (setf current-coeff -1))
  126. ((eq term '*) nil)
  127. ((eq term '+) nil)
  128. ((eq term '-)
  129. (setf current-coeff (- current-coeff)))
  130. ((numberp term)
  131. (if (eq (car (last (member term eq))) term)
  132. (setf free (* current-coeff term))
  133. (setf current-coeff (* current-coeff term))))
  134. (t
  135. (setf (gethash term coeffs)
  136. (+ (or (gethash term coeffs) 0) current-coeff))
  137. (setf current-coeff 1))))
  138. (list coeffs free)))