#math #scala #matrix #matrix-inverse
#математика #scala #матрица #матрица-обратная
Вопрос:
О, да, мне действительно нужен быстрый ввод от кого-то, у кого нет глаз создателя. Согласно моим scalacheck
тестам, здесь что-то не так… но я действительно недостаточно знаю об этом, чтобы понять, где это неправильно.
case class Matrix(_1: (Float, Float, Float, Float), _2: (Float, Float, Float, Float),
_3: (Float, Float, Float, Float), _4: (Float, Float, Float, Float)) extends Immutable {
def invert = {
val _11 = _2._2 * _3._3 * _4._4 - _2._2 * _3._4 * _4._3 - _3._2 * _2._3 * _4._4
_3._2 * _2._4 * _4._3 _4._2 * _2._3 * _3._4 - _4._2 * _2._4 * _3._3
val _21 = -_2._1 * _3._3 * _4._4 _2._1 * _3._4 * _4._3 _3._1 * _2._3 * _4._4
-_3._1 * _2._4 * _4._3 - _4._1 * _2._3 * _3._4 _4._1 * _2._4 * _3._3
val _31 = _2._1 * _3._2 * _4._4 - _2._1 * _3._4 * _4._2 - _3._1 * _2._2 * _4._4
_3._1 * _2._4 * _4._2 _4._1 * _2._2 * _3._4 - _4._1 * _2._4 * _3._2
val _41 = -_2._1 * _3._2 * _4._3 _2._1 * _3._3 * _4._2 _3._1 * _2._2 * _4._3
-_3._1 * _2._3 * _4._2 - _4._1 * _2._2 * _3._3 _4._1 * _2._3 * _3._2
val _12 = -_1._2 * _3._3 * _4._4 _1._2 * _3._4 * _4._3 _3._2 * _1._3 * _4._4
-_3._2 * _1._4 * _4._3 - _4._2 * _1._3 * _3._4 _4._2 * _1._4 * _3._3
val _22 = _1._1 * _3._3 * _4._4 - _1._1 * _3._4 * _4._3 - _3._1 * _1._3 * _4._4
_3._1 * _1._4 * _4._3 _4._1 * _1._3 * _3._4 - _4._1 * _1._4 * _3._3
val _32 = -_1._1 * _3._2 * _4._4 _1._1 * _3._4 * _4._2 _3._1 * _1._2 * _4._4
-_3._1 * _1._4 * _4._2 - _4._1 * _1._2 * _3._4 _4._1 * _1._4 * _3._2
val _42 = _1._1 * _3._2 * _4._3 - _1._1 * _3._3 * _4._2 - _3._1 * _1._2 * _4._3
_3._1 * _1._3 * _4._2 _4._1 * _1._2 * _3._3 - _4._1 * _1._3 * _3._2
val _13 = _1._2 * _2._3 * _4._4 - _1._2 * _2._4 * _4._3 - _2._2 * _1._3 * _4._4
_2._2 * _1._4 * _4._3 _4._2 * _1._3 * _2._4 - _4._2 * _1._4 * _2._3
val _23 = -_1._1 * _2._3 * _4._4 _1._1 * _2._4 * _4._3 _2._1 * _1._3 * _4._4
-_2._1 * _1._4 * _4._3 - _4._1 * _1._3 * _2._4 _4._1 * _1._4 * _2._3
val _33 = _1._1 * _2._2 * _4._4 - _1._1 * _2._4 * _4._2 - _2._1 * _1._2 * _4._4
_2._1 * _1._4 * _4._2 _4._1 * _1._2 * _2._4 - _4._1 * _1._4 * _2._2
val _43 = -_1._1 * _2._2 * _4._3 _1._1 * _2._3 * _4._2 _2._1 * _1._2 * _4._3
-_2._1 * _1._3 * _4._2 - _4._1 * _1._2 * _2._3 _4._1 * _1._3 * _2._2
val _14 = -_1._2 * _2._3 * _3._4 _1._2 * _2._4 * _3._3 _2._2 * _1._3 * _3._4
-_2._2 * _1._4 * _3._3 - _3._2 * _1._3 * _2._4 _3._2 * _1._4 * _2._3
val _24 = _1._1 * _2._3 * _3._4 - _1._1 * _2._4 * _3._3 - _2._1 * _1._3 * _3._4
_2._1 * _1._4 * _3._3 _3._1 * _1._3 * _2._4 - _3._1 * _1._4 * _2._3
val _34 = -_1._1 * _2._2 * _3._4 _1._1 * _2._4 * _3._2 _2._1 * _1._2 * _3._4
-_2._1 * _1._4 * _3._2 - _3._1 * _1._2 * _2._4 _3._1 * _1._4 * _2._2
val _44 = _1._1 * _2._2 * _3._3 - _1._1 * _2._3 * _3._2 - _2._1 * _1._2 * _3._3
_2._1 * _1._3 * _3._2 _3._1 * _1._2 * _2._3 - _3._1 * _1._3 * _2._2
val det = _1._1 * _11 _1._2 * _21 _1._3 * _31 _1._4 * _41
if (det == 0) this
else Matrix(
(_11, _12, _13, _14),
(_21, _22, _23, _24),
(_31, _32, _33, _34),
(_41, _42, _43, _44)
) * (1 / det)
}
def *(f: Float) = Matrix(
(_1._1 * f, _1._2 * f, _1._3 * f, _1._4 * f),
(_2._1 * f, _2._2 * f, _2._3 * f, _2._4 * f),
(_3._1 * f, _3._2 * f, _3._3 * f, _3._4 * f),
(_4._1 * f, _4._2 * f, _4._3 * f, _4._4 * f)
)
}
Кроме того, могу ли я загрузить эту матрицу в OpenGL или я должен сначала ее транспонировать. Я действительно всегда путаюсь в этой математике.
Комментарии:
1. пожалуйста, скажите мне, что это сгенерированный код…
2. Я написал это вручную по примеру…
3. О, боже. Это была пустая трата времени.
Ответ №1:
Инвертировать матрицу обычно плохая идея, потому что вычисления могут быть плохо обусловлены.
Если вы хотите решить систему уравнений, лучше сделать это, используя что-то вроде разложения LU и подстановки вперед-назад, особенно если вы можете повторно использовать разложение для решения для нескольких векторов правой стороны.
По этой ссылке показан пример Java для исключения Гаусса с поворотом.
Вот еще одна мысль: может быть, вы можете просто использовать библиотеки Java, такие как Apache Commons Math, преемник JAMA, в вашем приложении?
Если вы имеете в виду конкретный случай, я бы рекомендовал ввести его в Wolfram Alpha, чтобы вы могли увидеть, каким должен быть ответ, прежде чем начать кодирование.
Ответ №2:
Я почти уверен, что Simplex3D реализует это вычисление (и, скорее всего, там это сделано правильно).
Ответ №3:
Если вы хотите поиграть с числами — непременно продолжайте и сделайте это сами — у вас есть несколько хороших предложений от Джеспера и даффимо (инвертирование матриц на практике бесполезно — посмотрите на разложение LU).
Однако, если вы просто хотите выполнить работуTM загляните в Scalala и Scalalab.
В любом случае вам понадобятся базовые знания линейной алгебры, которая является невероятно полезной математикой для многих областей.
Ответ №4:
Посмотрите на обратимую матрицу: аналитическое решение в Википедии. Весь набор вычислений вверху вычисляет смежную матрицу, из которой вычисляется определитель, и тогда обратное значение 1 / det
умножается на смежную матрицу.
Весь расчет записан явно для матрицы 4 x 4 в вашем коде, поэтому, если в нем есть ошибка, потребуется некоторое усилие, чтобы проверить все это. Статьи Википедии объясняют, как это должно работать.
Комментарии:
1. Стоит отметить, что для больших матриц (даже 4×4) это не эффективный способ выполнения вычислений.