Подтвердить что ты не робот

Матричные преобразования; концепции и теории, есть ли свободные ресурсы для обучения практически?

В последнее время мне очень нравятся графики и графики рендеринга из координат, и я увлекаюсь использованием матриц для преобразования пространств координат.

Я смог успешно масштабировать и инвертировать пространственные координатные пространства, но теперь мой аппетит разгорается.:)

Где я могу найти ясный, информативный, (бесплатный) учебный материал по матрицам, матричную математику, особенно применительно к 2 и 3 мерным пространствам?

4b9b3361

Ответ 1

Оригинальный ответ: Я не уверен, если вам понравится, как математические курсы обычно вводят матрицы. Как программист, вы могли бы быть счастливее с захватом любой достойной 3D-графики. У него наверняка должны быть очень конкретные матрицы 3x3. Также узнайте те, которые научат вас проективные преобразования (проективная геометрия - очень красивая область низкоразмерной геометрии и простая в программировании).

Мини-курс в матричной математике с Python 3

Содержание:

  • Матрицы [Vector, __add__, reflect_y, rotate, dilate, transform]
  • Матрицы: перегружены [Matrix, __add__, __str__, __mul__, zero, det, inv, __pow__]
  • Бонус: Сложные номера
  • Матрицы: эволюция (R). Это уже в процессе создания (там резюме в конце)

Предисловие: Основываясь на моем опыте преподавания, я думаю, что курсы, на которые ссылаются другие, - очень хорошие курсы. Это означает, что если ваша цель заключается в понимании матриц, как это делают математики, вы должны всеми способами получить весь курс. Но если ваши цели более скромные, здесь я стараюсь что-то более скроенное вашим потребностям (но все же написанное с целью передать многие теоретические концепции, что противоречит моим первоначальным советам.)

Как использовать:

  • Это сообщение длинное. Вы можете подумать о том, чтобы напечатать это и идти медленно, как одна часть в день.
  • Код имеет важное значение. Это курс для программистов. Упражнения также необходимы.
  • Вы должны посмотреть на компаньона кода, который содержит весь этот код и многое другое
  • Это "2 по цене 1" особенное: вы также можете узнать Python 3 здесь. И комплексные числа.
  • Я очень ценю любую попытку прочитать это (официально ли я могу претендовать на самую длинную должность?), поэтому не стесняйтесь комментировать, если вы что-то не понимаете (а также если вы это делаете).

1. Матрицы

Векторы

Прежде, чем матрицы придут к векторам. Вы точно знаете, как обращаться с 2- и 3- мерными векторами:

class Vector:
    """This will be a simple 2-dimensional vector.

    In case you never encountered Python before, this string is a
    comment I can put on the definition of the class or any function.
    It just one of many cool features of Python, so learn it here!

    """

    def __init__(self, x, y): 
        self.x = x
        self.y = y

теперь вы можете написать

v = Vector(5, 3)
w = Vector(7, -1)

но это не очень весело. Добавьте более полезные методы:

    def __str__(self: 'vector') -> 'readable form of vector':
        return '({0}, {1})'.format(self.x, self.y)

    def __add__(self:'vector', v: 'another vector') -> 'their sum':
        return Vector(self.x + v.x, self.y + v.y)

    def __mul__(self:'vector', number: 'a real number') -> 'vector':
        '''Multiplies the vector by a number'''
        return Vector(self.x * number, self.y * number)

Это делает вещи более интересными, как мы теперь можем писать:

print(v + w * 2)

и получите ответ (19, 1) красиво напечатанный как вектор (если примеры выглядят незнакомыми, подумайте, как этот код будет выглядеть на С++).

Transformations

Теперь все здорово писать 1274 * w, но вам нужно больше векторных операций для графики. Вот некоторые из них: вы можете перевернуть вектор вокруг точки (0,0), вы можете отражать его вокруг оси x или y, вы можете вращать его по часовой стрелке или против часовой стрелки (здесь неплохо рисовать рисунок).

Сделайте несколько простых операций:

    ...

    def flip(self:'vector') -> 'vector flipped around 0':
        return Vector(-self.x, -self.y)

    def reflect_x(self:'vector') -> 'vector reflected around x axis':
        return Vector(self.x, -self.y)


print(v.flip(), v.reflect_x())
  • Вопрос: можно ли выразить flip(...) с помощью операций, которые у меня были ниже? Что насчет reflect_x?

Теперь вы можете задаться вопросом, почему я пропустил reflect_y. Ну, это потому, что я хочу, чтобы вы остановились на мгновение и напишите свою собственную версию. Хорошо, здесь моя:

    def reflect_y(self:'vector') -> 'vector reflected around y axis':
        return self.flip().reflect_x()

Посмотрите, если вы посмотрите, как эта функция вычисляет, это на самом деле довольно тривиально. Но неожиданно произошла удивительная вещь: я смог написать преобразование, используя только существующие преобразования flip и reflect_x. Насколько мне известно, reflect_y может быть определен в производном классе без доступа к x и y, и он все равно будет работать!

Математики называли бы эти операторы функций. Они скажут, что reflect_y - оператор, полученный по составу операторов flip и reflect_x, который равен обозначается символом reflect_y = flip ○ reflect_x (вы должны увидеть маленький круг, символ Unicode 25CB).

  • Примечание: Я буду свободно использовать символ = отныне, чтобы обозначить, что две операции дают тот же результат, что и в предыдущем абзаце. Это "математический =", который не может быть выражен как программа.

Итак, если я делаю

print(v.reflect_y())

Получаю результат (-5, 3). Идите и покажите это!

  • Вопрос: Рассмотрим композицию reflect_y ◦ reflect_y. Как бы вы это назвали?

Повороты

Эти операции были приятными и полезными, но вам, вероятно, интересно, почему так медленно вводить вращения. Хорошо, здесь я иду:

    def rotate(self:'vector', angle:'rotation angle') -> 'vector':
        ??????

В этот момент, если вы знаете, как вращать векторы, вы должны продолжить и заполнить вопросительные знаки. В противном случае, пожалуйста, примите меня за еще один простой случай: вращение против часовой стрелки на 90 градусов. Это не сложно сделать на листе бумаги:

    def rotate_90(self:'vector') -> 'rotated vector':
        new_x = - self.y
        new_y =   self.x
        return Vector(new_x, new_y)

Попытка

x_axis = Vector(1, 0)
y_axis = Vector(0, 1)

print(x_axis.rotate_90(), y_axis.rotate_90())

теперь дает (0, 1) (-1, 0). Запустите его самостоятельно!

  • Вопрос: Докажите, что flip = rotate_90 ◦ rotate_90.

Во всяком случае, я больше не буду скрывать секретный ингредиент:

import math   # we'll need math from now on
  ...

class Vector:

      ...

    def rotate(self:'vector', angle:'rotation angle') -> 'rotated vector':
        cos = math.cos(angle)
        sin = math.sin(angle)
        new_x = cos * self.x - sin * self.y
        new_y = sin * self.x + cos * self.y
        return Vector(new_x, new_y)

Теперь попробуйте что-нибудь по строкам:

print(x_axis.rotate(90), y_axis.rotate(90))

Если вы ожидаете того же результата, что и раньше, (0, 1) (-1, 0), вы обязательно будете разочарованы. Этот код печатает:

(-0.448073616129, 0.893996663601) (-0.893996663601, -0.448073616129)

и мальчик, это уродливо!

  • Обозначение: Я скажу, что мы применили операцию rotate(90) к x в приведенном выше примере. Знания, которые мы получили, это то, что rotate(90) != rotate_90.

  • Вопрос: Что здесь произошло? Как выразить rotate_90 в терминах rotate? Как выразить flip в терминах rotate?

дилатации

Эти вращения, безусловно, полезны, но они не все, что вам нужно, даже для 2D-графики. Рассмотрим следующие преобразования:

    def dilate(self:'vector', axe_x:'x dilation', axe_y:'y dilation'):
        '''Dilates a vector along the x and y axes'''
        new_x = axe_x * self.x
        new_y = axe_y * self.y
        return Vector(new_x, new_y)

Эта вещь dilate расширяет оси x и y, возможно, по-другому.

  • Упражнение: Заполните вопросительные знаки в dilate(?, ?) = flip, dilate(?, ?) = reflect_x.

Я буду использовать эту функцию dilate, чтобы продемонстрировать, что математики называют коммутацией: т.е. для каждого значения параметров a, b, c, d вы можете быть уверены, что

dilate(a, b) ◦ dilate(c, d) = dilate(c, d) ◦ dilate(a, b)
  • Упражнение: Докажите. Кроме того, верно ли, что для всех возможных значений параметров, которые были ниже, будет?

    • rotate(a) ◦ rotate(b) = rotate(b) ◦ rotate(a)
    • dilate(a, b) ◦ rotate(c) = rotate(c) ◦ dilate(a, b)
    • rotate(a) ◦ __mul__(b) = __mul__(b) ◦ rotate(a)

Матрицы

Обобщите все, что у нас было здесь, наши операторы на векторе x

  • flip, reflect_x, *, rotate(angle), dilate(x, y)

из которого можно было бы создать действительно сумасшедший материал, например

  • flip ◦ rotate(angle) ◦ dilate(x, y) ◦ rotate(angle_2) ◦ reflect_y + reflect_x = ???

Когда вы создаете все более сложные выражения, можно надеяться на какой-то порядок, который внезапно уменьшит все возможные выражения до полезной формы. Не бойся! Магически каждое выражение вышеприведенной формы может быть упрощено до

    def ???(self:'vector', parameters):
        '''A magical representation of a crazy function'''
        new_x = ? * self.x + ? * self.y
        new_y = ? * self.x + ? * self.y
        return Vector(new_x, new_y)

с некоторыми числами и/или параметрами вместо ? s.

  • Пример: Определите, что значения '?' для __mul__(2) ◦ rotate(pi/4)
  • Другой пример: Тот же вопрос для dilate(x, y) ◦ rotate(pi/4)

Это позволяет написать универсальную функцию

    def transform(self:'vector', m:'matrix') -> 'new vector':
        new_x = m[0] * self.x + m[1] * self.y
        new_y = m[2] * self.x + m[3] * self.y
        return Vector(new_x, new_y)

который возьмет любой 4-кортеж чисел, называемый матрицей, и применит его к вектору x. Вот пример:

rotation_90_matrix = (0, -1, 1, 0)
print(v, v.rotate_90(), v.transform(rotation_90_matrix))

который печатает (5, 3) (-3, 5) (-3, 5). Обратите внимание, что если вы примените transform с любая матрица к происхождению, вы все равно получаете начало:

origin = Vector(0, 0)
print(origin.transform(rotation_90_matrix))
  • Упражнение: какие кортежи m описывают flip, dilate(x, y), rotate(angle)?

Поскольку мы расстаемся с классом Vector, здесь упражнение для тех, кто хочет протестировать как их математическое знание вектора, так и навыки Питона:

  • Последняя битва: Добавьте в класс Vector все векторные операции, которые вы можете придумать (сколько стандартных операторов вы можете перегрузить для векторов?).. li >

2. Матрицы: перегруженные

Как мы выяснили в предыдущем разделе, матрицу можно рассматривать как сокращенную форму, которая позволяет нам кодировать векторную операцию простым способом. Например, rotation_90_matrix кодирует поворот на 90 градусов.

Матричные объекты

Теперь, когда мы переходим от векторов к матрицам, мы должны, во всяком случае, иметь класс для матрицы. Более того, в этой функции Vector.transform(...) выше роль матрицы была несколько искажена. Это более обычное для m фиксироваться при изменении вектора, поэтому отныне нашими преобразованиями будут методы класса матрицы:

class Matrix:

    def __init__(self:'new matrix', m:'matrix data'):
        '''Create a new matrix.

        So far a matrix for us is just a 4-tuple, but the action
        will get hotter once The (R)evolution happens!

        '''
        self.m = m

    def __call__(self:'matrix', v:'vector'):
        new_x = self.m[0] * v.x + self.m[1] * v.y
        new_y = self.m[2] * v.x + self.m[3] * v.y
        return Vector(new_x, new_y)

Если вы не знаете Python, __call__ перегружает значение (...) для матриц, поэтому я могу использовать стандартную нотацию для матрицы, действующей на вектор. Кроме того, матрицы обычно записываются с использованием одной прописной буквы:

J = Matrix(rotation_90_matrix)
print(w, 'rotated is', J(w))
  • Упражнение: повторите этот пример с помощью матриц из предыдущего упражнения.

Добавление

Теперь давайте выясним, что еще мы можем сделать с матрицами. Помните, что матрица m - это действительно просто способ кодирования операции на векторах. Обратите внимание, что для двух функций m1(x) и m2(x) я могу создать новую функцию (используя lambda notation) m = lambda x: m1(x) + m2(x). Оказывается, если m1 и m2 были привязаны матрицами, вы также можете кодировать этот m с помощью матриц!

  • Упражнение: Подумайте о любых трудностях, которые могут возникнуть с этим утверждением.

Вам просто нужно добавить свои данные, например (0, 1, -1, 0) + (0, 1, -1, 0) = (0, 2, -2, 0). Здесь, как добавить два кортежа в Python, с некоторыми очень полезными и высоко питоническими методами:

    def __add__(self:'matrix', snd:'another matrix'):
        """This will add two matrix arguments.

        snd is a standard notation for second argument.
        (i for i in array) is Python powerful list comprehension.
        zip(a, b) is used to iterate over two sequences together

        """

        new_m = tuple(i + j for i, j in zip(self.m, snd.m))
        return Matrix(new_m)

Теперь мы можем писать выражения типа J + J или даже J + J + J, но чтобы увидеть результаты, нам нужно выяснить, как печатать матрицу. Возможным способом было бы напечатать 4-кортеж чисел, но пусть намек от функции Matrix.__call__, что числа должны быть организованы в блок 2x2:

    def as_block(self:'matrix') -> '2-line string':
        """Prints the matrix as a 2x2 block.

        This function is a simple one without any advanced formatting.
        Writing a better one is an exercise.

        """

        return ('| {0} {1} |\n' .format(self.m[0], self.m[1]) +
                '| {0} {1} |\n' .format(self.m[2], self.m[3]) )

Если вы посмотрите на эту функцию в действии, вы заметите, что есть кое-что для улучшения:

print((J + J + J).as_block())
  • Упражнение: напишите более приятную функцию Matrix.__str__, которая будет охватывать номера и печатать их в полях фиксированной длины.

Теперь вы можете написать матрицу для вращения:

def R(a: 'angle') -> 'matrix of rotation by a':
    cos = math.cos(a)
    sin = math.sin(a)
    m = ( ????? )
    return Matrix(m)
  • Упражнение: Изучите код Vector.rotate(self, angle) и заполните вопросительные знаки. Тест с

    from math import pi        
    print(R(pi/4) + R(-pi/4))
    

Умножение

Самое главное, что мы можем сделать с однопараметрическими функциями, состоит в следующем: f = lambda v: f1(f2(v)). Как отразить это с помощью матриц? Это требует от нас изучения того, как работает Matrix(m1) ( Matrix(m2) (v)). Если вы развернете его, вы заметите, что

m(v).x = m1[0] * (m2[0]*v.x + m2[1]*v.y) + m1[1] * (m2[2]*v.x + m2[3]*v.y)

и аналогично для m(v).y, который, если вы открываете круглые скобки, выглядит подозрительно похожим на Matrix.__call__ с использованием нового кортежа m, такого, что m[0] = m1[0] * m2[0] + m1[2] * m2[2]. Поэтому давайте рассмотрим это как подсказку для нового определения:

    def compose(self:'matrix', snd:'another matrix'):
        """Returns a matrix that corresponds to composition of operators"""

        new_m = (self.m[0] * snd.m[0] + self.m[1] * snd.m[2],
                 self.m[0] * snd.m[1] + self.m[1] * snd.m[3],
                 ???,
                 ???) 
        return Matrix(new_m)
  • Упражнение: Заполните вопросительные знаки здесь. Протестируйте его с помощью

    print(R(1).compose(R(2)))
    print(R(3))
    
  • Математическое упражнение: Докажите, что R(a).compose(R(b)) всегда совпадает с R(a + b).

Теперь позвольте мне сказать правду: эта функция compose на самом деле означает, что математики решили умножить матрицы. Это имеет смысл как обозначение: A * B - это матрица, которая описывает оператор A ○ B, и, как мы увидим ниже, есть более серьезные причины называть это "умножение".

Чтобы начать использовать умножение в Python, нам нужно просто заказать его в Matrix класс:

    class Matrix:

          ...

        __mul__ = compose
  • Упражнение: Вычислить (R(pi/2) + R(pi)) * (R(-pi/2) + R(pi)). Сначала попробуйте найти ответ на листе бумаги.

Правила для + и *

Сделайте хорошее имя для матрицы, соответствующей оператору dilate(a, b). Теперь нет ничего плохого в D(a, b), но я буду используйте возможность ввести стандартную нотацию:

def diag(a: 'number', b: 'number') -> 'diagonal 2x2 matrix':
    m = (a, 0, 0, b)
    return Matrix(m)

Попробуйте print(diag(2, 12345)), чтобы понять, почему он называется диагональной матрицей.

Поскольку состав операций был найден раньше, чтобы быть не всегда коммутативным, оператор * также не всегда будет коммутативным для матриц.

  • Упражнение: вернитесь и обновите предмет коммутации, если это необходимо. Затем приведем примеры матриц a, b, сделанных из R и diag, такой, что A * B не равен B * A.

Это несколько странно, так как умножение на числа всегда является коммутативным и вызывает вопрос о том, действительно ли compose называться __mul__. Здесь довольно много правил, которые + и * удовлетворяют:

  • A + B = B + A
  • A * (B + C) = A * B + A * C
  • (A + B) * C = A * C + B * C
  • (A * B) * C = A * (B * C)
  • Существует операция с именем A - B и (A - B) + B = A

    • Упражнение: Докажите эти утверждения. Как определить A - B в терминах +, * и diag? Что означает A - A? Добавьте метод __sub__ в класс Matrix. Что произойдет, если вы вычислите R(2) - R(1)*R(1)? Что должно быть равно?

Равенство (A * B) * C = A * (B * C) называется ассоциативностью и особенно приятно, так как это означает, что нам не нужно беспокоиться о том, чтобы положить круглые скобки в выражение формы A * B * C:

print(R(1) * (diag(2,3) * R(2)))
print((R(1) * diag(2,3)) * R(2))

Найдем аналоги с регулярными числами 0 и 1 и вычитанием:

zero = diag(0, 0)
one = diag(1, 1)     

Со следующими легко проверяемыми дополнениями:

  • A + zero = A
  • A * zero = zero
  • A * one = one * A = A

правила становятся полными, в том смысле, что для них есть короткое имя: кольцевые аксиомы. Математики, таким образом, скажут, что матрицы образуют кольцо, и они действительно всегда используют символы + и *, когда говорят о кольцах, и мы тоже будем.

Используя правила, можно легко вычислить выражение из предыдущего раздела:

(R(pi/2) + R(pi)) * (R(-pi/2) + R(pi)) = R(pi/2) * R(-pi/2) +  ... = one + ...
  • Упражнение: Завершите это. Докажите, что (R(a) + R(b)) * (R(a) - R(b)) = R(2a) - R(2b).

Аффинные преобразования

Время для возврата к тому, как мы определили матрицы: они являются ярлыками для некоторых операций, которые вы можете делать с векторами, поэтому вы можете на самом деле рисовать. Вы можете взять ручку или посмотреть на материалы, которые другие предложили увидеть примеры различных преобразований плоскости.

Среди преобразований мы будем искать аффинных, тех, кто везде "одинаково" (без изгибов). Например, вращение вокруг некоторой точки (x, y) квалифицируется. Теперь это не может быть выражено как lambda v: A(v), но in может быть записано в виде lambda v: A(v) + b для некоторой матрицы a и vector b.

  • Упражнение: найдите a и b, так что поворот на pi/2 вокруг точки (1, 0) имеет форму выше. Являются ли они уникальными?

Заметим, что для каждого вектора существует аффинное преобразование, являющееся сдвигом вектором.

Аффинное преобразование может растягивать или расширять формы, но оно должно действовать одинаково везде. Теперь я надеюсь, что вы считаете, что область любой фигуры изменяется под постоянным числом при трансформации. Для преобразования, заданного матрицей a, этот коэффициент называется детерминантом a и может быть вычислен с применением формулы для области к двум векторам A(x_axis) и A(y_axis):

    def det(self: 'matrix') -> 'determinant of a matrix':
        return self.m[0]*self.m[3] - self.m[1] * self.m[2]

Как проверка работоспособности, diag(a, b).det() равен A * B.

  • Упражнение: Проверьте это. Что происходит, когда один из аргументов равен 0? Когда он отрицательный?

Как вы можете видеть, определитель матрицы вращения всегда один и тот же:

from random import random
r = R(random())
print (r, 'det =', r.det())

Одна интересная вещь о det заключается в том, что она мультипликативна (ее вид следует из определения, если вы медитируете достаточно долго):

A = Matrix((1, 2, -3, 0))
B = Matrix((4, 1, 1, 2))
print(A.det(), '*', B.det(), 'should be', (A * B).det())

Inverse

Полезная вещь, которую вы можете сделать с матрицами, - написать систему из двух линейных уравнений

A.m[0]*v.x + A.m[1]*v.y = b.x
A.m[2]*v.x + A.m[3]*v.y = b.y

проще: A(v) = b. Пусть решают систему, когда учат в (некоторых) средних школах: умножить первое уравнение на A.m[3], второе на -Am 1 и добавить ( если есть сомнения, сделайте это на листе бумаги), чтобы решить для v.x.

Если вы действительно пробовали это, вы должны получить A.det() * v.x = (A.m[3]) * b.x + (-A.m[1]) * b.y, что предполагает, что вы всегда можете получить v путем умножения b на некоторую другую матрицу. Эта матрица называется обратным к a:

    def inv(self: 'matrix') -> 'inverse matrix':
        '''This function returns an inverse matrix when it exists,
        or raises ZeroDivisionError when it doesn't. 

        '''
        new_m = ( self.m[3] / self.det(), -self.m[1] / self.det(),
                  ????? )
        return Matrix(new_m)

Как вы видите, этот метод терпит неудачу, когда определитель матрицы равен нулю. Если вы действительно хотите, вы можете поймать это искушение с помощью:

try:
    print(zero.inv())
except ZeroDivisionError as e: ...
  • Упражнение: Завершите метод. Докажите, что обратная матрица не существует, когда self.det() == 0. Напишите метод для деления матриц и проверки его. Использовать обратную матрицу для решения уравнения A(v) = x_axis (a было определено выше).

Полномочия

Основное свойство обратной матрицы состоит в том, что A * A.inv() всегда равно one

  • Упражнение: убедитесь сами. Объясните, почему это должно быть так из определения обратной матрицы.

Итак, математики обозначают A.inv() выражением a -1. Как насчет того, что мы пишем хорошая функция для использования обозначения A ** n для a n? Заметим, что наивный цикл for i in range(n): answer *= self равен O (| n |), который, конечно, слишком медленный, потому что это можно сделать со сложностью log |n|:

    def __pow__(self: 'matrix', n:'integer') -> 'n-th power':
        '''This function returns n-th power of the matrix.

        It does it more efficiently than a simple for cycle. A
        while loop goes over all bits of n, multiplying answer
        by self ** (2 ** k) whenever it encounters a set bit.

        ...
  • Упражнение: Заполните детали этой функции. Протестируйте его с помощью

    X, Y = A ** 5, A ** -5 print (X, Y, X * Y, sep = '\n')

Эта функция работает только для целочисленных значений n, хотя для некоторых матриц мы также можем определить дробную мощность, такую ​​как квадратный корень (другими словами, матрица b такая, что B * B = A).

  • Упражнение: Найдите квадратный корень из diag(-1, -1). Это единственный возможный ответ? Найдите пример матрицы, которая не имеет квадратного корня.

Бонус: Комплексные номера

Здесь я расскажу вам об этом в одном разделе! Поскольку это сложный вопрос, я, скорее всего, потерпит неудачу, поэтому, пожалуйста, простите меня заранее.

Во-первых, аналогично тому, как мы имеем матрицы zero и one, мы можем сделать матрицу из любого действительного числа, выполнив diag(number, number). Матрицы этой формы могут быть добавлены, вычтены, умножены, перевернуты, и результаты будут имитировать то, что происходит с самими числами. Поэтому для всех практических целей можно сказать, что, например, diag(5, 5) равно 5.

Однако Python еще не знает, как обрабатывать выражения формы A + 1 или 5 * B, где a и b являются матрицами. Если вам интересно, вы должны непременно пойти и сделать следующее упражнение или посмотреть на мою реализацию (в которой используется классная функция Python, называемая декоратором); иначе, просто знайте, что он был реализован.

  • Упражнение для гуру: Измените операторы в классе Matrix, чтобы во всех стандартных операциях, где один из операндов является матрицей, а другой - числом, число автоматически преобразуется в diag. Также добавьте сравнение для равенства.

Вот пример теста:

print( 3 * A - B / 2 + 5 )

Теперь здесь первое интересное комплексное число: матрица J, введенная в начале и равная Matrix((0, 1, -1, 0)), имеет смешное свойство, которое J * J == -1 (попробуйте!). Это означает, что J, конечно, не является нормальным числом, но, как я только что сказал, матрицы и числа легко смешиваются. Например,

(1 + J) * (2 + J) == 2 + 2 * J + 1 * J + J * J = 1 + 3 * J

используя перечисленные выше правила. Что произойдет, если мы проверим это на Python?

(1 + J) * (2 + J) == 1 + 3*J

Это должно с радостью сказать True. Другой пример:

(3 + 4*J) / (1 - 2*J) == -1 + 2*J 

Как вы могли догадаться, математики не называют эти "сумасшедшие числа", но они делают что-то похожее - они называют выражениями комплексных чисел формы a + b*J. Поскольку они все еще являются экземплярами нашего класса Matrix, мы можем выполнять довольно много операций с такими: сложение, вычитание, умножение, деление, власть - все это уже реализовано! Не удивительны ли матрицы?

Я упустил вопрос о том, как напечатать результат операции, например E = (1 + 2*J) * (1 + 3*J), чтобы он выглядел как выражение с J, а не с матрицей 2x2. Если вы внимательно изучите его, вы увидите, что вам нужно напечатать левый столбец этой матрицы в формате ... + ...J (просто еще одна приятная вещь: это точно E(x_axis)!) Те, кто знает разницу между str() и repr(), должны видеть естественно назвать функцию, которая будет выражать такую ​​форму как repr().

  • Упражнение: Запишите функцию Matrix.__repr__, которая будет делать именно это, и попробуйте с ней некоторые тесты, например (1 + J) ** 3, сначала вычисляя результат на бумаге, а затем пробуя его с помощью Python.

  • Математический вопрос: Каков детерминант a + b*J? Если вы знаете, что такое абсолютное значение комплексного числа: как они связаны? Какова абсолютная величина a? of a*J?

3. Матрицы: эволюция (R)

В заключительной части этой трилогии мы увидим, что все является матрицей. Мы начнем с общих матриц M x N и узнаем, как векторы можно рассматривать как матрицы 1 x N и почему числа совпадают с диагональными матрицами. В качестве примечания мы рассмотрим комплексные числа как матрицы 2 x 2.

Наконец, мы научимся писать аффинные и проективные преобразования с использованием матриц.

Итак, запланированные классы [MNMatrix, NVector, Affine, Projective].

Думаю, если бы ты смог нести меня до сих пор, ты мог бы заинтересоваться этим продолжением, поэтому я хотел бы услышать, буду ли я продолжать это (и где, поскольку я почти уверен, м за пределы разумной длины одного документа).

Ответ 2

В MIT есть много материалов по математическим курсам в Интернете http://ocw.mit.edu/OcwWeb/Mathematics/. Когда у вас есть основы, у них также есть заметки о физике.

Ответ 5

Одна из лучших книг для новичков - Карл Майер "Матричный анализ и прикладная линейная алгебра".

Вы можете просмотреть всю книгу онлайн здесь (хотя у нее есть водяной знак авторского права): http://www.matrixanalysis.com/DownloadChapters.html

Возможно, вы захотите взглянуть на главу 5 стр. 326 - 332, который охватывает повороты в трехмерной компьютерной графике

Ответ 6

Вы можете захотеть взглянуть на геометрическую линейную алгебру И-Сюнь Лин, Исиньон Линь (ISBN: 9812560874). Книга специально ориентирована на то, что вы хотите (линейные преобразования 2 и 3-мерных векторных пространств) и рассматривает ее с геометрическим подходом в полной, прогрессивной детализации (300 страниц для каждого измерения). Я боюсь, что это не бесплатно купить, но вы сможете найти его в любой хорошей университетской библиотеке. В противном случае Bookfinder должен помочь вам получить его по относительно скромной цене.

Ответ 7

Джим Хефферон бесплатно Линейная алгебра учебник действительно хорош. В отличие от слишком большого количества бесплатных электронных книг, Джим ясно нашел время, чтобы создать превосходного читателя и введение в линейную алгебру. Он не слишком обременен формальным математическим письмом, которое часто слишком плотно с теоремами и доказательствами, чтобы быть легко понятным. Он также содержит множество действительно отличных примеров реальных приложений для линейных алгебр - преобразование координат - всего лишь один пример. Вы не можете победить цену, и она также поставляется с дополнительными решениями для упражнений.

P.S. Если преобразования координат - это ваше дело, вы можете быть заинтересованы в дифференциальной геометрии после того, как вы закончите с линейной алгеброй.

Ответ 8

Это информация, которую я нашел. Некоторые из них могут быть ценными для вас:

Теория:

(Поиск "Matrices" в книгах Google дает вам много лекций, некоторые из которых напрямую связаны с преобразованиями - это является одним из первых результатов, но я приветствую вас, чтобы проверить больше.)

Я также рекомендую (я не знаю, правильно ли это слово, я просто изучаю английский). Вы, чтобы искать такую ​​информацию в одной из этих книг (хотя они не являются бесплатными, но вы можете найти большие части старых в Google Книгах):

У каждого из них есть раздел о математических драгоценных камнях - и там есть много опрятных трюков. Эти книги стоят каждого цента.

Есть также графические процессоры GPU, поэтому вы также можете попробовать их.

Практика:

Если я найду больше, я отредактирую и добавлю ссылки сюда, но, честно говоря, я нашел эти ссылки примерно за 10 минут использования Google. Самый популярный в мире браузер хранит данные обо всем - и да, "все" означает также матрицы.

Cheers, Mate.

Ответ 9

Я думаю, вам стоит потратить несколько дней на точечные продукты и перекрестные продукты с векторами в 3D. Затем изучите связь между триггером и векторами. После этого матрицы будут иметь для вас гораздо больше смысла.

Ответ 10

Курс MIT-OCW по линейной алгебре Гильберта Странга. Невероятные лекции невероятного человека; если ваше понимание матриц происходит исключительно из источников программирования (например, MATLAB), то курс по линейной алгебре определенно даст вам основы для сумасшедших вещей с матрицами.

http://www.ocw.cn/OcwWeb/Mathematics/18-06Spring-2005/VideoLectures/index.htm