Этот вопрос довольно старый, но он все еще высоко ценится в Google в 2019 году, а также некоторые более ранние ответы устарели, поэтому я подумал, что поделюсь возможным решением.
В модели вводятся некоторые области с тестом на наличие переданного параметра:
class Post
scope :where_author_ids, ->(ids){ where(author_id: ids.split(‘,’)) if ids }
scope :where_topic_ids, ->(ids){ where(topic_id: ids.split(‘,’)) if ids }
Затем в контроллере вы можете просто установить столько фильтров, сколько пожелаете, например:
def list
@posts = Post.where_author_ids(params[:author_ids])
.where_topic_ids(params[:topic_ids])
.where_other_condition_ids(params[:other_condition_ids])
.order(:created_at)
Параметр может быть одним значением или разделенным запятыми списком значений, оба работают нормально.
Если param не существует, он просто пропускает предложение where и не фильтрует его по определенным критериям. Если параметр существует, но его значение является пустой строкой, он будет «отфильтровывать» все.
Конечно, это решение не подходит для любых обстоятельств. Если у вас есть страница просмотра с несколькими фильтрами, но при первом открытии вы хотите показать все свои данные, а не данные, пока не нажмете кнопку «Отправить» или аналогичную (как это сделал бы контроллер), вам придется слегка подправить ее. ,
Я попробовал SQL-инъекцию, и rails, кажется, хорошо справляется с обеспечением безопасности, насколько я могу видеть.
Исходный ответ: Я не уверен, понравится ли вам, как математические курсы обычно вводят матрицы. Как программист, вы, возможно, будете счастливее взять любую приличную книгу по 3D-графике. У него обязательно должны быть очень конкретные матрицы 3x3. Также найдите те, которые научат вас проективным преобразованиям (проективная геометрия - очень красивая область низкоразмерной геометрии и ее легко программировать).
Содержание:
[Вектор, __add__, отражать_y, вращать, расширять, преобразовать]
[Матрица, __add__, __str__, __mul__, zero, det , inv, __pow __]
Предисловие: Основываясь на моем преподавательском опыте, я думаю, что курсы, на которые ссылаются другие, очень хорошие курсы . Это означает, что если вашей целью является понимание матриц так, как это делают математики, то вы непременно должны пройти весь курс. Но если ваши цели более скромные, вот моя попытка сделать что-то более адаптированное к вашим потребностям (но все же написанное с целью передать многие теоретические концепции, что отчасти противоречит моему первоначальному совету).
Как использовать:
Перед матрицами идут векторы. Вы наверняка знаете, как работать с двумерными и трехмерными векторами:
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's 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)
, красиво напечатанный как вектор (если примеры выглядят незнакомыми, подумайте, как этот код будет выглядеть на C ++).
Теперь здорово иметь возможность писать 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 (...)
, используя описанные ниже операции? А как насчет reflection_x
? Теперь вы можете задаться вопросом, почему я пропустил reflection_y
. Ну, это потому, что я хочу, чтобы вы на мгновение остановились и написали свою собственную версию. Хорошо, вот мой:
def reflect_y(self:'vector') -> 'vector reflected around y axis':
return self.flip().reflect_x()
Видите ли, если вы посмотрите, как эта функция вычисляет, на самом деле это довольно тривиально. Но вдруг произошло удивительное: Мне удалось написать преобразование, используя только существующие преобразования flip
и Reflection_x
. Мне все равно, Reflection_y
можно определить в производном классе без доступа к x
и y
, и это все равно будет работать!
Математики назвали бы это функции операторы . Они сказали бы, что reflection_y
- это оператор, полученный композицией операторов flip
и reflection_x
, что является
обозначается отражать_y = перевернуть ○ отражать_x
(вы должны увидеть маленький кружок, символ Юникода 25CB
).
=
, чтобы обозначить, что две операции производят одинаковый результат, как в предыдущем абзаце. Это «математическое =
», которое не может быть выражено как программа . Так что, если я сделаю
print(v.reflect_y())
, я получу результат (- 5, 3 )
. Иди и представь это!
Reflection_y ◦ Reflection_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 (?,?) = Отражать_x
. Я буду использовать эта функция dilate
демонстрирует то, что математики называют коммутативностью : то есть для каждого значения параметров a
, b
, c
, d
вы можете быть уверены, что
dilate(a, b) ◦ dilate(c, d) = dilate(c, d) ◦ dilate(a, b)
Exercise: Докажите это. Кроме того, верно ли, что для всех возможных значений параметров будут выполняться те, которые ниже?
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
, reflection_x
, *
, rotate (angle)
, dilate (x, y)
, из которого можно сделать действительно сумасшедшие вещи вроде
flip ◦ rotate (angle) ◦ dilate (x, y) ◦ rotate (angle_2) ◦ Reflection_y + Reflection_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)
. Обратите внимание, что если вы примените преобразование
с Не бойся! Волшебным образом каждое выражение в приведенной выше форме может быть упрощено до
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)
. Обратите внимание, что если вы примените преобразование
с Не бойся! Волшебным образом каждое выражение в приведенной выше форме может быть упрощено до
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)
. Обратите внимание, что если вы примените преобразование
с Определите, каковы значения "?" предназначены для __ 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)
. Обратите внимание, что если вы примените преобразование
с Определите, каковы значения "?" предназначены для __ 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)
. Обратите внимание, что если вы примените преобразование
с и применить его к вектору x
. Вот пример:
rotation_90_matrix = (0, -1, 1, 0)
print(v, v.rotate_90(), v.transform(rotation_90_matrix))
, который печатает (5, 3) (-3, 5) (-3, 5)
. Обратите внимание, что если вы примените преобразование
с и применить его к вектору x
. Вот пример:
rotation_90_matrix = (0, -1, 1, 0)
print(v, v.rotate_90(), v.transform(rotation_90_matrix))
, который печатает (5, 3) (-3, 5) (-3, 5)
. Обратите внимание, что если вы примените преобразование
с
любая матрица в начало координат, вы все равно получите исходную точку:
origin = Vector(0, 0)
print(origin.transform(rotation_90_matrix))
m
описывают переворот
, dilate (x, y)
, rotate (angle)
? Когда мы расстаемся с классом Vector
, вот упражнение для тех, кто хочет проверить как свои знания векторной математики, так и навыки Python:
Vector
все векторные операции, которые вы можете придумать (сколько стандартных операторов вы можете перегрузить для векторов? Посмотрите мой ответ). Как мы выяснили в предыдущем разделе, матрицу можно рассматривать как сокращение, которое позволяет нам кодировать векторную операцию простым способом. Например, 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)
я могу создать новую функцию (используя лямбда-нотацию ) 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's 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
, но чтобы увидеть результаты, мы должны выяснить, как напечатать матрицу.
числа и распечатайте их в полях фиксированной длины.
Теперь вы можете написать матрицу для вращения:
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)
и заполните вопросительные знаки. Тест с
из math import pi
печать (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
, который, если вы откроете круглые скобки, выглядит подозрительно похожим
to Matrix .__ вызов __
с использованием нового кортежа 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)))
печать (R (3))
Математическое упражнение: Докажите, что R (a) .compose (R (b))
всегда совпадает с R (a + b)
.
Теперь позвольте мне сказать правду: эта функция compose
на самом деле представляет собой то, как математики решили умножить матриц.
Это имеет смысл в виде записи: A * B
- это матрица, описывающая оператор A ○ B
, и, как мы увидим далее, есть более глубокие причины называть это «умножением» как хорошо.
Чтобы начать использовать умножение в Python, все, что нам нужно сделать, это упорядочить его так в Matrix
class:
class Matrix:
...
__mul__ = compose
(R (pi / 2) + R (pi)) * (R (-pi / 2) + R (pi))
. Попробуйте сначала найти ответ на листе бумаги. +
и *
Давайте придумаем хорошее название для матрицы, которая соответствует расширению ( а, б) оператор
. Теперь все в порядке с 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
. Это несколько странно, поскольку умножение чисел всегда коммутативно, и возникает вопрос, может ли составлять
действительно заслуживает того, чтобы называться __ 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 + ноль = A
A * ноль = ноль
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)
подходит. Теперь это нельзя выразить как лямбда v: A (v)
, но можно записать в виде лямбда v: A (v) + b
для некоторой матрицы A
и вектор 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
.
Как видите, определитель матрицы вращения всегда один и тот же:
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())
С помощью матриц вы можете сделать полезную вещь - написать систему двух линейных уравнений
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
. Давайте решим систему, как преподают в (некоторых) средних школах: умножьте первое уравнение на Am [3]
, второе на -Am 1 и сложите (если сомневаетесь, сделайте это на лист бумаги), чтобы найти vx
.
Если вы действительно попробовали, у вас должно было быть A.det () * vx = (Am [3]) * bx + ( -Am [1]) * на
, что предполагает, что вы всегда можете получить 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 . Как насчет того, чтобы написать s почему математики обозначают A.inv ()
как A
-1 . Как насчет того, чтобы написать s почему математики обозначают A.inv ()
как A
-1 . Как насчет того, чтобы написать
удобная функция для использования обозначения A ** n
для A
n ? Обратите внимание, что наивный для i в диапазоне (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)
. Это единственно возможный ответ?
Найдите пример матрицы, у которой не квадратный корень. Здесь я собираюсь познакомить вас с предметом ровно в одном разделе! Поскольку это сложный предмет, я, скорее всего, проиграю, поэтому, пожалуйста, простите меня заранее.
Во-первых, аналогично тому, как у нас есть матрицы ноль
и единица
, мы можем сделать матрицу из любого действительного числа, выполнив 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
? из a * J
?
В заключительной части этой трилогии мы увидим, что все является матрицей. Мы начнем с общих матриц M x N
и выясним, как векторы можно рассматривать как матрицы 1 x N
и почему числа такие же, как диагональные матрицы. В качестве примечания мы исследуем комплексные числа как матрицы 2 x 2
.
Наконец, мы научимся писать аффинные и проективные преобразования с использованием матриц.
Итак, запланированные классы ] [MNMatrix, NVector, Affine, Projective]
.
Думаю, если бы вы могли терпеть меня до этого момента, вас могло бы заинтересовать это продолжение, поэтому я хотел бы услышать, следует ли мне продолжить это (и где,
MIT имеет много материалов своих курсов по математике в Интернете по адресу http : //ocw.mit.edu/OcwWeb/Mat Mathematics/ . Когда вы освоите основы, у них также будут онлайн-заметки по физике.
это http://en.wikipedia.org/wiki/Computer_graphics . двумя ключевыми концепциями являются http://mathworld.wolfram.com/LinearTransformation.html и http://mathworld.wolfram.com/AffineTransformation.html .
Этот документ MIT необходим для получения глубоких знаний об основах трансформации.
Вы можете посмотреть Геометрическая линейная алгебра И-Сюн Линь, Иксюн Лин (ISBN: 9812560874). Книга специально ориентирована на то, что вы хотите (линейные преобразования 2-х и 3-х мерных векторных пространств), и рассматривает это с геометрическим подходом во всех деталях, прогрессивных деталях (300 страниц для каждого измерения). Боюсь, это не бесплатно, но вы сможете найти его в любой хорошей университетской библиотеке. В противном случае Bookfinder должен помочь вам получить его по относительно скромной цене.
Одна из лучших книг для начинающих - «Матричный анализ и прикладная линейная алгебра» Карла Мейера.
Вы можете просмотреть всю книгу онлайн здесь (хотя на ней есть водяной знак с авторским правом): http://www.matrixanalysis.com/DownloadChapters.html
Возможно, вам стоит взглянуть на главу 5, стр. 326–332, который охватывает вращения в трехмерной компьютерной графике
Бесплатный учебник Линейной алгебры Джима Хефферона действительно хорош. В отличие от слишком многих бесплатных электронных книг, Джим явно нашел время, чтобы создать отличного читателя и ввести в линейную алгебру. Он не обременен формальным математическим письмом, которое часто слишком насыщено теоремами и доказательствами, чтобы их было легко понять. Он также содержит множество действительно отличных примеров реальных приложений линейной алгебры - преобразования координат являются лишь одним из примеров. Вы не можете превзойти цену, и это также включает дополнительные решения для упражнений.
PS Если вы занимаетесь преобразованием координат, вас может заинтересовать дифференциальная геометрия после того, как вы закончите с линейной алгеброй.
Those are the information that I found. Some of them might be valuable to You:
Theory:
(Searching for "Matrices" at Google books gives You lots of lecutures, some of which are directly connected with transformations - this is one of the first results, but I cheer You to check more.)
I also encourage (I don't know if this is the right word, I am just learning English) You, to look for this kind of information in one of those books (though they are not free, but You can find large parts of older ones on Google Books):
Each of those has section about math gems - and there are lots of neat tricks there. Those books are worth every cent.
There are also GPU Programming gems, so You might try them too.
Practice:
Если я найду больше , Я буду редактировать и добавлять ссылки здесь, но, честно говоря, я нашел эти ссылки примерно за 10 минут использования Google. Самый популярный в мире браузер хранит данные обо всем - и да, «все» также означает матрицы.
Ура, приятель.
Я думаю, вам следует потратить несколько дней на точечные произведения и кросс-произведения с векторами в 3D. Затем изучите связь между тригонометром и векторами. После этого матрицы станут для вас более понятными.
Курс MIT-OCW по линейной алгебре Гилберта Стренга. Невероятные лекции невероятного человека; если ваше понимание матриц основано исключительно на программных источниках (таких как MATLAB), то курс линейной алгебры определенно даст вам основы, чтобы делать сумасшедшие вещи с матрицами.
http://www.ocw.cn/OcwWeb/Mat Mathematics /18-06Spring-2005/VideoLectures/index.htm