Инверсия матрицы Scala

#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) это не эффективный способ выполнения вычислений.