矩阵变换;概念和理论,是否有实际学习的免费资源? [英] Matrix transforms; concepts and theory, are there any free resources for learning practically?

查看:135
本文介绍了矩阵变换;概念和理论,是否有实际学习的免费资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近很乐意从坐标渲染图表和图表,我很着迷使用矩阵来转换坐标空间。

I've been having fun rendering charts and graphs from co-ordinates lately, and I'm fascinated by using matrices to transform co-ordinate spaces.

I已经能够成功地缩放和反转二维坐标空间,但现在我的胃口很大。 :)

I've been able to successfully scale and invert 2 dimensional co-ordinate spaces, but now my appetite is whetted. :)

我在哪里可以获得关于矩阵,矩阵数学的清晰,信息丰富,(免费)的教育材料,特别是适用于二维和三维空间?

Where can I go for clear, informative, (free), educational material on matrices, matrix math, especially as applies to 2 and 3 dimensional space?

推荐答案

原始答案:我不确定您是否会喜欢数学课程通常如何引入矩阵。作为程序员,你可能会更喜欢抓住任何体面的3D图形书。它当然应该具有非常具体的3x3矩阵。还要找出能教你投影变换的那些(投影几何是一个非常美丽的领域)低维几何,易于编程)。

Original answer: I'm not sure if you will like how mathematical courses typically introduce matrices. As a programmer you might be happier with grabbing any decent 3D graphics book. It should certainly have very concrete 3x3 matrices. Also find out the ones that will teach you projective transformations (projective geometry is a very beautiful area of low-dimensional geometry and easy to program).

内容:


  1. 矩阵 [Vector,__ add__,reflect_y ,旋转,扩张,变换]

  2. 矩阵:重载 [Matrix,__ add __,_ _ ttr __,__ mul__,零,det,inv,__ pop __]

  3. 奖励:复杂数字

  4. 矩阵:(R)进化。它已经在制作中(最后有一个摘要)

  1. Matrices [Vector, __add__, reflect_y, rotate, dilate, transform]
  2. Matrices: Overloaded [Matrix, __add__, __str__, __mul__, zero, det, inv, __pow__]
  3. Bonus: Complex numbers
  4. Matrices: The (R)evolution. It's already in the making (there's a summary at the end)

前言:根据我的教学经验,我认为其他人引用的课程非常好课程。这意味着如果你的目标是像数学家一样理解矩阵,那么你应该通过各种手段来完成全部课程。但是如果你的目标更加温和,那么我的尝试就是根据你的需求量身定做的东西(但仍然是为了传达许多理论概念而写的,与我原来的建议相矛盾。)

Preface: Based on my teaching experience, I think that the courses referenced by others are very good courses. That means if your goal is understanding matrices as mathematicians do, than you should by all means get the whole course. But if your goals are more modest, here's my try at something more tailored to your needs (but still written with the goal to convey many theoretical concepts, kind of contradicting my original advice.)

如何使用:


  • 这篇文章很长。你可能会考虑打印这个并且变慢,比如每天一个部分。

  • 代码是必不可少的。这是程序员的课程。练习也很重要。

  • 你应该 看看代码伴侣 ,其中包含所有这些代码等等

  • 这是2的价格为1特价:你也可以在这里学习Python 3。复杂的数字。

  • 我非常重视任何读这篇文章的尝试(我是否正式获得有史以来最长的职位?),如果你不明白某事,请随时评论(如果你这样做的话)。

  • This post is long. You might consider printing this and going slow, like one part a day.
  • Code is essential. This is a course for programmers. Exercises are essential too.
  • You should take a look at the code companion which contains all this code and much more
  • It's "2 for the price of 1" special: you can also learn Python 3 here. And complex numbers.
  • I'll highly value any attempt to read this (do I officially qualify for the longest post ever?), so feel free to comment if you don't understand something (and also if you do).

在矩阵到达向量之前。你肯定知道如何处理二维和三维向量:

Before matrices come vectors. You sure know how to handle the 2- and 3- dimensional vectors:

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)

但它本身并不是很有趣。让我们添加更多有用的方法:

but it's not much fun by itself. Let's add more useful methods:

    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)

这让事情变得更有趣,因为我们现在可以写:

That makes things more interesting as we can now write:

print(v + w * 2)

并获得答案 (19,1)很好地打印为矢量(如果示例看起来不熟悉,请考虑这段代码在C ++中的外观)。

and get the answer (19, 1) nicely printed as a vector (if the examples look unfamiliar, think how this code would look in C++).

现在能够写 1274 * w 但是你需要更多的图形矢量操作。以下是其中一些:你可以在(0,0)点附近翻转矢量,你可以在 x 或 y 轴,您可以顺时针或逆时针旋转它(这里最好画一幅画)。

Now it's all cool to be able to write 1274 * w but you need more vector operations for the graphics. Here are some of them: you can flip the vector around (0,0) point, you can reflect it around x or y axis, you can rotate it clockwise or counterclockwise (it's a good idea to draw a picture here).

让我们做一些简单的操作:

Let's do some simple operations:

    ...

    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())




  • 问题:是否有可能表达翻转(...)使用我下面的操作?怎么样 reflect_x

    • Question: is it possible to express flip(...) using the operations I had below? What about reflect_x?
    • 现在你可能想知道为什么我省略 reflect_y 。嗯,这是因为我希望你停下片刻并编写你自己的版本。好的,这是我的:

      Now you may wonder why I omitted reflect_y. Well, it's because I want you to stop for a moment and write your own version of it. Ok, here's mine:

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

      看,如果你看看这个函数如何计算,它实际上是非常微不足道的。但突然发生了一件令人惊奇的事情:我只能使用现有的转换 flip reflect_x 来编写转换。对于我所关心的一切, reflect_y 可以在派生类中定义,而无需访问 x ,它仍然有用!

      See, if you look how this function computes, it's actually quite trivial. But suddenly an amazing thing happened: I was able to write a transformation using only the existing transformations flip and reflect_x. For all I care, reflect_y could be defined in a derived class without access to x and y and it would still work!

      数学家会将这些函数称为运算符。他们会说 reflect_y 是由运营商的组合获得的运算符 flip reflect_x 这是
      reflect_y = flip○reflect_x 表示(你应该看到一个小圆圈,一个Unicode符号 25CB )。

      Mathematicians would call these functions operators. They would say that reflect_y is an operator obtained by composition of operators flip and reflect_x which is denoted by reflect_y = flip ○ reflect_x (you should see the small circle, a Unicode symbol 25CB).


      • 注意:我会很自由从现在开始使用 = 符号表示两个操作产生相同的结果,如上面的段落所示。这是一个数学 = 不能表示为一个程序

      • Note: I will quite freely use the = symbol from now to denote that two operations produce the same result, like in the paragraph above. This is a "mathematical =", which cannot be expressed as a program.

      所以如果我这样做

      print(v.reflect_y())
      

      我得到了结果( - 5,3)。去拍照吧!

      I get the result (-5, 3). Go and picture it!


      • 问题:考虑作文reflect_y◦refos_y。你怎么称呼它?

      • Question: Consider a composition reflect_y ◦ reflect_y. How would you name it?

      这些操作既好又实用,但你很可能想知道为什么引入轮换这么慢。好的,我走了:

      Those operations were nice and useful, but you are probably wondering why am so slow to introduce rotations. Ok, here I go:

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

      此时,如果你知道如何旋转矢量,你应该继续填写问题分数。否则请耐心等待一个简单的案例:逆时针旋转 90 度。这个并不难在一张纸上画出:

      At this point, if you know how to rotate vectors, you should go on and fill in the question marks. Otherwise please bear with me for one more simple case: counterclockwise rotation by 90 degrees. This one is not hard to draw on a piece of paper:

          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◦rotation_90

      • Question: Prove that flip = rotate_90 ◦ rotate_90.

      无论如何,我不会长时间隐藏秘密成分:

      Anyway, I won't hide the secret ingredient for longer:

      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),你一定很失望。该代码打印:

      If you expect the same result as before, (0, 1) (-1, 0), you're bound to be disappointed. That code prints:

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

      和男孩,难看!


      • 符号:我会说我们将操作 rotate(90)应用到 x 在上面的例子中。我们获得的知识是 rotate(90)!= rotate_90

      • Notation: I will say that we applied operation rotate(90) to x in the example above. The knowledge we gained is that rotate(90) != rotate_90.

      问题: 这里发生了什么?如何用 rotate 来表达 rotate_90 ?如何以旋转来表达翻转

      Question: What happened here? How to express rotate_90 in terms of rotate? How to express flip in terms of rotate?

      这些旋转肯定是有用的,但它们并不是你需要做的所有事情,即使是2D图形也是如此。考虑以下转换:

      Those rotations are certainly useful, but they are not everything you need to do even the 2D graphics. Consider the following transformations:

          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)
      

      扩张的事情以可能不同的方式扩展 x y 轴。

      This dilate thing dilates the x and y axes in a possibly different way.


      • 练习:在 dilate(?,?)中填写问号=翻转扩张(?,?)= reflect_x

      • Exercise: Fill in the question marks in dilate(?, ?) = flip, dilate(?, ?) = reflect_x.

      我将使用这个 dilate 函数来演示数学家称之为交换性的东西:即,对于每个参数值 a b c d 你可以肯定

      I will use this dilate function to demonstrate a thing mathematicians call commutativity: that is, for every value of parameters a, b, c, d you can be sure that

      dilate(a, b) ◦ dilate(c, d) = dilate(c, d) ◦ dilate(a, b)
      




      • 练习:证明一下。此外,对于以下所有可能的参数值是否正确?

        • Exercise: Prove it. Also, is it true that for all possible values of parameters those below would hold?


          • 旋转(a)◦旋转(b)=旋转(b)◦旋转(a)

          • 扩张(a,b)◦转动(c)=旋转(c)◦扩张(a,b)

          • 旋转(a)◦__mul__(b)= __mul __(b)◦旋转(a)

          • 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)

          让我们总结一下我们在这里所有的东西,我们的运算符在vector x

          Let's summarize all the stuff we had around here, our operators on vector x


          • 翻转 reflect_x * 旋转(角度)扩张(x,y)

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

          从中可以制作一些非常疯狂的东西,比如

          from which one could make some really crazy stuff like


          • 翻转◦旋转(角度)◦扩张(x,y)◦旋转(angle_2)◦refos_y+ reflect_x = ???

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

          当你创建越来越复杂的表达式时,人们会希望某种顺序会突然将所有可能的表达式减少为有用的形式。不要害怕!奇怪的是,上面表格的每个表达都可以简化为

          As you create more and more complicated expressions, one would hope for some kind of order that would suddenly reduce all possible expressions to a useful form. Fear not! Magically, every expression of the form above can be simplified to

              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。

          with some numbers and/or parameters instead of ?s.


          • 示例:弄清楚'?'的值是什么 __ mul __(2)◦wall(pi / 4)

          • 另一个例如: 扩展相同的问题(x,y)◦Rating(pi / 4)

          • Example: Work out what the values of '?' are for __mul__(2) ◦ rotate(pi/4)
          • Another example: Same question for dilate(x, y) ◦ rotate(pi/4)

          这允许我们编写一个通用函数

          This allows us to write a universal function

              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 。这是一个例子:

          which would take any 4-tuple of numbers, called matrix, and apply it to vector x. Here's an example:

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

          打印(5 ,3)( - 3,5)( - 3),。请注意,如果您使用
          转换与任何矩阵一起应用于原点,您仍然可以获得原点:

          which prints (5, 3) (-3, 5) (-3, 5). Note that if you apply transform with any matrix to origin, you still get origin:

          origin = Vector(0, 0)
          print(origin.transform(rotation_90_matrix))
          




          • 练习:描述的元组 m 是什么翻转扩张(x,y)旋转(角度)

            • Exercise: what are the tuples m that describe flip, dilate(x, y), rotate(angle)?
            • 当我们分享 Vector 课程时,这里有一个练习给想要测试的人他们的矢量数学知识和Pythonic技能:

              As we part with the Vector class, here's an exercise for those who want to test both their vector math knowledge and Pythonic skills:


              • 最后一战:加入向量类你可以提出的所有向量运算(你可以为向量重载多少个标准运算符?看看我的答案)。

              • The final battle: Add to the Vector class all vector operations that you can come up with (how many of standard operators can you overload for vectors? Check out my answer).

              正如我们在上一节中发现的那样,矩阵可以被认为是一种简写,它允许我们以简单的方式对矢量运算进行编码。例如, rotation_90_matrix 将旋转编码90度。

              As we found out in the previous section, a matrix can be thought of a shorthand that allows us to encode a vector operation in a simple way. For example, rotation_90_matrix encodes the rotation by 90 degrees.

              现在我们将注意力从向量转移到矩阵,我们也应该为矩阵提供一个类
              。此外,在该函数 Vector.transform(...)之上,矩阵的作用有些歪曲。在向量更改时修复 m 更常见,所以从现在起我们的转换将是矩阵类的方法:

              Now as we shift our attention from vectors to matrices, we should by all means have a class for matrix as well. Moreover, in that function Vector.transform(...) above the role of the matrix was somewhat misrepresented. It's more usual for m to be fixed while vector changes, so from now on our transformations will be methods of matrix class:

              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 __ 为矩阵重载(...)的含义,因此我可以在向量上使用标准符号表示代理。此外,矩阵通常使用单个大写字母编写:

              If you don't know Python, __call__ overloads the meaning of (...) for matrices so I can use the standard notation for a matrix acting on a vector. Also, the matrices are usually written using a single uppercase letter:

              J = Matrix(rotation_90_matrix)
              print(w, 'rotated is', J(w))
              




              • 练习:使用上一练习中的矩阵重复此示例。

                • Exercise: repeat this example with matrices from the previous exercise.
                • 现在,我们来看看我们还能做些什么矩阵。请记住矩阵 m 实际上只是一种在向量上编码operaton的方法。请注意,对于两个函数 m1(x) m2(x)我可以创建一个新函数(使用 lambda表示法 m = lambda x:m1(x)+ m2(x )。事实证明,如果 m1 m2 被矩阵包围,你也可以编码 m 使用矩阵

                  Now, let's find out what else we can do with matrices. Remember that matrix m is really just a way to encode an operaton on vectors. Note that for two functions m1(x) and m2(x) I can create a new function (using lambda notation) m = lambda x: m1(x) + m2(x). It turns out if m1 and m2 were enconded by matrices, you can also encode this m using matrices!


                  • 练习:通过思考您对此声明可能遇到的任何困难。

                  • Exercise: Think through any difficulties you might have with this statement.

                  您只需要添加其数据,例如(0, 1,-1,0)+(0,1,-1,0)=(0,2,-2,0)。这里是如何在Python中添加两个元组,一些非常有用和高度Pythonic技术:

                  You just have to add its data, like (0, 1, -1, 0) + (0, 1, -1, 0) = (0, 2, -2, 0). Here's how to add two tuples in Python, with some very useful and highly Pythonic techniques:

                      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 这样的表达式,但是要看到我们必须弄清楚如何打印矩阵的结果。一种可能的方法是打印一个4元组的数字,但让我们从 Matrix .__ call __ 函数中提示,这些数字应该被组织成一个 2x2 block:

                  Now we can write expressions like J + J or even J + J + J, but to see the results we have to figure out how to print a Matrix. A possible way would be to print a 4-tuple of numbers, but let's take a hint from the Matrix.__call__ function that the numbers should be organized into a 2x2 block:

                      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]) )
                  

                  如果你看一下这个功能,你会发现还有一些改进空间:

                  If you look at this function in action you'll notice there is some room for improvement:

                  print((J + J + J).as_block())
                  




                  • 练习:写一个更好的函数 Matrix .__ str __ 将围绕
                    数字并在固定长度的字段中打印它们。

                    • Exercise: write a nicer function Matrix.__str__ that will round the numbers and print them in the fields of fixed length.
                    • 现在你应该可以编写矩阵进行轮换:

                      Now you should be able to write the matrix for rotation:

                      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)的代码并填写问号。从数学导入中测试

                        • Exercise: Examine the code for Vector.rotate(self, angle) and fill in the question marks. Test with

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


                        • 我们可以用单参数函数做的最重要的事情就是组合它们: f = lambda v:f1(f2(v))。如何用矩阵镜像?这要求我们检查矩阵(m1)(矩阵(m2)(v))的工作原理。如果你展开它,你会注意到

                          The most important thing we can do with one-parameter functions is compose them: f = lambda v: f1(f2(v)). How to mirror that with matrices? This requires us to examine how Matrix(m1) ( Matrix(m2) (v)) works. If you expand it, you'll notice that

                          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] 。所以让我们把它作为新定义的暗示:

                          and similarly for m(v).y, which, if you open the parentheses, looks suspiciously similar to Matrix.__call__ using a new tuple m, such that m[0] = m1[0] * m2[0] + m1[2] * m2[2]. So let's take this as a hint for a new definiton:

                              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)
                          




                          • 练习:在此处填写问号。测试它

                            • Exercise: Fill in the question marks here. Test it with

                              print(R(1).compose(R(2)))
                              print(R(3))
                              


                            • 数学习题证明 R(a).compose(R(b))始终与 R(a + b)相同。

                              现在让我说实话:这个撰写函数实际上是怎样的数学家决定乘以矩阵。
                              这作为一种表示法是有意义的: A * B 是一个描述运算符 A○B 的矩阵,而且我们接下来会看到更深层次的理由称这种'乘法'。

                              Now let me tell the truth: this compose function is actually how mathematicians decided to multiply matrices. This makes sense as a notation: A * B is a matrix that decribes operator A ○ B, and as we'll see next there are deeper reasons to call this 'multiplication' as well.

                              要开始在Python中使用乘法,我们所要做的就是订购它所以在矩阵
                              类:

                              To start using multiplication in Python all we have to do is to order it so in a Matrix class:

                                  class Matrix:
                              
                                        ...
                              
                                      __mul__ = compose
                              




                              • 锻炼:计算(R(pi / 2)+ R(pi))*(R(-pi / 2)+ R(pi ))。试着先在一张纸上找到答案。

                                • Exercise: Compute (R(pi/2) + R(pi)) * (R(-pi/2) + R(pi)). Try to find the answer yourself first on a piece of paper.
                                • 让我们为与对应的矩阵建立一个好名字扩张(a,b)运营商。现在 D(a,b)没有任何问题,但是我将
                                  使用机会引入标准符号:

                                  Let's make some good name for the matrix that corresponds to the dilate(a, b) operator. Now there's nothing wrong with D(a, b), but I'll use a chance to introduce a standard notation:

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

                                  尝试 print(diag(2,12345))查看为什么它被称为对角线矩阵。

                                  Try print(diag(2, 12345)) to see why it's called a diagonal matrix.

                                  由于以前发现的操作组成并不总是可交换的, * 运算符不会总是可交换的对于矩阵也。

                                  As the composition of operations was found before to be not always commutative, * operator won't be always commutative for matrices either.


                                  • 练习:如有必要,请返回并刷新交换事物。然后举例说明矩阵 A B ,由 R 和 diag
                                    使 A * B 不等于 B * A

                                  • Exercise: go back and refresh the commutativity thing if necessary. Then give examples of matrices A, B, made from R and diag, such that A * B is not equal to B * A.

                                  这有点奇怪,因为数字的乘法总是可交换的,并提出了一个问题是否 compose 确实应该被称为 __ mul __ 。这里有很多规则 + * 满足:

                                  This is somewhat strange, since multiplication for numbers is always commutative, and raises the question whether compose really deserves to be called __mul__. Here's quite a lot of rules that + and * do satisfy:


                                  1. A + B = B + A

                                  2. A *(B + C)= A * B + A * C

                                  3. (A + B)* C = A * C + B * C

                                  4. (A * B)* C = A *(B * C)

                                  5. 有一项名为 A - B 的操作(A - B)+ B = A


                                  • 练习:证明这些陈述。如何根据 + * A - B >和 diag A - A 等于什么?将方法 __ sub __ 添加到类 Matrix 。如果你计算 R(2) - R(1)* R(1)会怎样?它应该等于什么?

                                  • Exercise: Prove these statements. How to define A - B in terms of +, * and diag? What does A - A equal to? Add the method __sub__ to the class Matrix. What happens if you compute R(2) - R(1)*R(1)? What should it be equal to?

                                  ( A * B)* C = A *(B * C)相等称为 associativity ,特别好,因为这意味着我们不必担心放括号表达式
                                  表格 A * B * C

                                  The (A * B) * C = A * (B * C) equality is called associativity and is especially nice since it means that we don't have to worry about putting parentheses in an expression of the form A * B * C:

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

                                  让我们找到常规数字的类似物 0 1 和减法:

                                  Let's find analogues to regular numbers 0 and 1 and subtraction:

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

                                  通过以下易于验证的新增内容:

                                  With the following easily verifiable additions:


                                  1. A + zero = A

                                  2. A *零=零

                                  3. A * one = 1 * A = A

                                  1. A + zero = A
                                  2. A * zero = zero
                                  3. A * one = one * A = A

                                  规则变得完整,因为它们有一个简短的名称: ring axioms
                                  因此数学家会说矩阵形成 ring ,他们确实总是使用符号 + * 在谈论戒指时,我们也应如此。

                                  the rules become complete, in the sense that there is a short name for them: ring axioms. Mathematicians thus would say that matrices form a ring, and they indeed always use symbols + and * when talking about rings, and so shall we.

                                  使用这些规则可以轻松计算上一节中的表达式:

                                  Using the rules it's possible to easily compute the expression from the previous section:

                                  (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)

                                    • Exercise: Finish this. Prove that (R(a) + R(b)) * (R(a) - R(b)) = R(2a) - R(2b).
                                    • 返回我们定义矩阵的方式的时间:它们是你可以用向量做的一些操作的快捷方式,所以它是你可以实际绘制的东西。您可能想要拿笔或查看其他人建议的材料以查看不同平面变换的示例。

                                      Time to return to how we defined matrices: they are a shortcut to some operations you can do with vectors, so it's something you can actually draw. You might want to take a pen or look at the materials that others suggested to see examples of different plane transformations.

                                      在转换中我们将寻找仿射那些,到处都是相同的人(没有弯曲)。例如,围绕某个点(x,y)的旋转符合条件。现在这个不能表示为 lambda v:A(v),但是可以用 lambda v:A(v)+的形式写出来b 对于某些矩阵 A 和向量 b

                                      Among the transformations we'll be looking for the affine ones, those who look 'the same' everywhere (no bending). For example, a rotation around some point (x, y) qualifies. Now this one cannot be expressed as lambda v: A(v), but in can be written in the form lambda v: A(v) + b for some matrix A and vector b.


                                      • 锻炼:找到 A b 这样在(1,0)点附近按 pi / 2 旋转具有上述表格。它们是唯一的吗?

                                      • Exercise: find the A and b such that a rotation by pi/2 around the point (1, 0) has the form above. Are they unique?

                                      请注意,对于每个向量,都有一个仿射变换,它是 shift 向量。

                                      Note that for every vector there is an affine transformation which is a shift by the vector.

                                      仿射变换可能会拉伸或扩大形状,但它应该以相同的方式在各处进行。现在我希望你相信任何数字的面积在变换下都会改变一个常数。对于矩阵 A 给出的转换,此系数称为 A 行列式,并且可以计算将区域的公式应用于两个向量 A(x_axis) A(y_axis)

                                      An affine transformation may stretch or dilate shapes, but it should do in the same way everywhere. Now I hope you believe that the area of any figure changes by a constant number under the transformation. For a transformation given by matrix A this coeffiecient is called the determinant of A and can be computed applying the formula for an area to two vectors A(x_axis) and 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

                                      As a sanity check, diag(a, b).det() is equal to a * b.


                                      • 锻炼:检查一下。当一个参数为0时会发生什么?当它是负数?

                                      • Exercise: Check this. What happens when one of arguments is 0? When it's negative?

                                      正如你所看到的,旋转矩阵的行列式始终是相同的:

                                      As you can see, the determinant of rotation matrix is always the same:

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

                                      关于 det 的一个有趣的事情是它是乘法的(如果你冥想足够长,它可以从定义中得出):

                                      One interesting thing about det is that it is multiplicative (it kind of follows from the definition if you meditate long enough):

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



                                      反向



                                      你可以用矩阵做一个有用的事情是写一个由两个线性方程组成的系统

                                      Inverse

                                      A useful thing you can do with matrices is write a system of two linear equations

                                      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

                                      in a simpler way: A(v) = b. Let's solve the system as they teach in (some) high schools: multiply first equation by A.m[3], second by -A.m1 and add (if in doubt, do this on a piece of paper) to solve for v.x.

                                      如果你真的尝试过,你应该有 A.det()* vx =(Am [3])* bx +(-Am [1])* by ,这表明您可以通过乘以 b <来获得 v / code>由其他矩阵组成。此矩阵称为 A

                                      If you really tried it, you should have got A.det() * v.x = (A.m[3]) * b.x + (-A.m[1]) * b.y, which suggests that you can always get v by multiplying b by some other matrix. This matrix is called inverse of 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)
                                      

                                      如您所见,此方法失败当矩阵的行列式为零时,响亮地。如果你真的想要你可以通过以下方式获得这个期望:

                                      As you see, this method fails loudly when determinant of matrix is zero. If you really want you can catch this expection with:

                                      try:
                                          print(zero.inv())
                                      except ZeroDivisionError as e: ...
                                      




                                      • 练习:完成方法。当 self.det()== 0 时,证明逆矩阵不存在。编写方法来划分矩阵并对其进行测试。使用逆矩阵求解方程 A(v)= x_axis A 如上所述)。

                                        • Exercise: Finish the method. Prove that inverse matrix doesn't exist when self.det() == 0. Write the method to divide matrices and test it. Use the inverse matrix to solve an equation A(v) = x_axis (A was defined above).
                                        • 逆矩阵的主要属性是 A * A.inv()总是等于一个

                                          The main property of inverse matrix is that A * A.inv() always equals to one


                                          • 锻炼:检查一下你自己。从逆矩阵的定义解释为什么应该如此。

                                          • Exercise: check that yourself. Explain why that should be so from the definition of inverse matrix.

                                          这就是为什么数学家表示 A.inv( ) A -1 。我们写一个
                                          漂亮的函数来为 A n使用 A ** n 表示法怎么样? ?请注意,范围内的天真(n):answer * = self 循环是O(| n |),这当然太慢,因为
                                          这可以完成复杂的 log | n |

                                          That's why mathematicians denote A.inv() by A-1. How about we write a nice function to use A ** n notation for An? Note that the naive for i in range(n): answer *= self cycle is O(|n|) which is certainly too slow, because this can be done with a complexity of 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.
                                          
                                                  ...
                                          




                                          • 练习:填写此功能的详细信息。测试它

                                            • Exercise: Fill in the details in this function. Test it with

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

                                              此函数仅适用于 n 的整数值,即使对于某些矩阵,我们也可以定义分数幂,例如平方根(在其他中) words, a matrix B such that B * B = A).

                                              This function only works for integer values of n, even though for some matrices we can also define a fractional power, such as square root (in other words, a matrix B such that B * B = A).


                                              • Exercise: Find a square root of diag(-1, -1). Is this the only possible answer?
                                                Find an example of matrix that doesn’t have a square root.

                                              • Exercise: Find a square root of diag(-1, -1). Is this the only possible answer? Find an example of matrix that doesn't have a square root.

                                              Here I’m going to introduce you to the subject in exactly one section!
                                              Since it’s a complex subject, I’m likely to fail, so please forgive me in advance.

                                              Here I'm going to introduce you to the subject in exactly one section! Since it's a complex subject, I'm likely to fail, so please forgive me in advance.

                                              First, similarly to how we have matrices zero and one, we can make a matrix out of any real number by doing diag(number, number). Matrices of that form can be added, subtracted, multiplied, inverted and the results would mimic what happens with the numbers themselves. So for all practical purposes, one can say that, e.g., diag(5, 5) is 5.

                                              First, similarly to how we have matrices zero and one, we can make a matrix out of any real number by doing diag(number, number). Matrices of that form can be added, subtracted, multiplied, inverted and the results would mimic what happens with the numbers themselves. So for all practical purposes, one can say that, e.g., diag(5, 5) is 5.

                                              However, Python doesn’t know yet how to handle expressions of the form A + 1 or 5 * B where A and B are matrices. If you’re interested, you should by all means go and do the following exercise or look at my implementation (which uses a cool Python feature called decorator); otherwise, just know that it’s been implemented.

                                              However, Python doesn't know yet how to handle expressions of the form A + 1 or 5 * B where A and B are matrices. If you're interested, you should by all means go and do the following exercise or look at my implementation (which uses a cool Python feature called decorator); otherwise, just know that it's been implemented.


                                              • Exercise for gurus: Change the operators in a Matrix class so that in all standard operations where one of operands is a matrix and another a number, the number is automatically converted to the diag matrix. Also add comparison for equality.

                                              • Exercise for gurus: Change the operators in a Matrix class so that in all standard operations where one of operands is a matrix and another a number, the number is automatically converted to the diag matrix. Also add comparison for equality.

                                              Here’s an example test:

                                              Here's an example test:

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

                                              Now here’s the first interesting complex number: the matrix J, introduced in the beginning and equal to Matrix((0, 1, -1, 0)), has a funny property that J * J == -1 (try it!). That means J is certainly not a normal number, but, as I just said, matrices and numbers easily mix together. For example,

                                              Now here's the first interesting complex number: the matrix J, introduced in the beginning and equal to Matrix((0, 1, -1, 0)), has a funny property that J * J == -1 (try it!). That means J is certainly not a normal number, but, as I just said, matrices and numbers easily mix together. For example,

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

                                              using the rules listed some time before. What happens if we test this in Python?

                                              using the rules listed some time before. What happens if we test this in Python?

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

                                              That should happily say True. Another example:

                                              That should happily say True. Another example:

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

                                              As you might have guessed, the mathematicians don’t call those ’crazy numbers’, but they do something similar - they call expressions of the form a + b*J complex numbers.
                                              Because those are still instances of our Matrix class, we can do quite a lot of operations with those: addition, subtraction, multiplication, division, power - it’s all already implemented! Aren’t matrices amazing?

                                              As you might have guessed, the mathematicians don't call those 'crazy numbers', but they do something similar - they call expressions of the form a + b*J complex numbers. Because those are still instances of our Matrix class, we can do quite a lot of operations with those: addition, subtraction, multiplication, division, power - it's all already implemented! Aren't matrices amazing?

                                              I have overlooked the question of how to print the result of operation like E = (1 + 2*J) * (1 + 3*J) so that it looks like an expression with J rather than a 2x2 matrix. If you examine it carefully,
                                              you’ll see that you need to print the left column of that matrix in the format ... + ...J (just one more nice thing: it’s exactly E(x_axis)!) Those who know the difference between str() and repr() should see it’s natural to name a function that would produce expression of such form as repr().

                                              I have overlooked the question of how to print the result of operation like E = (1 + 2*J) * (1 + 3*J) so that it looks like an expression with J rather than a 2x2 matrix. If you examine it carefully, you'll see that you need to print the left column of that matrix in the format ... + ...J (just one more nice thing: it's exactly E(x_axis)!) Those who know the difference between str() and repr() should see it's natural to name a function that would produce expression of such form as repr().


                                              • Exercise: Write the function Matrix.__repr__ that would do exactly that and try some tests with it, like (1 + J) ** 3, first computing the result on paper and then trying it with Python.

                                              • Exercise: Write the function Matrix.__repr__ that would do exactly that and try some tests with it, like (1 + J) ** 3, first computing the result on paper and then trying it with Python.

                                              Math question: What is the determinant of a + b*J? If you know what the absolute value of complex number is: how they are connected? What is the absolute value of a? of a*J?

                                              Math question: What is the determinant of a + b*J? If you know what the absolute value of complex number is: how they are connected? What is the absolute value of a? of a*J?

                                              In the final part of this trilogy we will see that everything is a matrix. We’ll start with general M x N matrices, and find out how vectors can be thought of as 1 x N matrices and why numbers are the same as diagonal matrices. As a side note we’ll explore the complex numbers as 2 x 2 matrices.

                                              In the final part of this trilogy we will see that everything is a matrix. We'll start with general M x N matrices, and find out how vectors can be thought of as 1 x N matrices and why numbers are the same as diagonal matrices. As a side note we'll explore the complex numbers as 2 x 2 matrices.

                                              Finally, we will learn to write affine and projective transformations using matrices.

                                              Finally, we will learn to write affine and projective transformations using matrices.

                                              So the classes planned are [MNMatrix, NVector, Affine, Projective].

                                              So the classes planned are [MNMatrix, NVector, Affine, Projective].

                                              I guess if you was able to bear with me until here, you could be interested in this sequel, so I’d like to hear if I should continue with this (and where, since I’m pretty much sure I’m beyond what considered reasonable length of a single document).

                                              I guess if you was able to bear with me until here, you could be interested in this sequel, so I'd like to hear if I should continue with this (and where, since I'm pretty much sure I'm beyond what considered reasonable length of a single document).

                                              这篇关于矩阵变换;概念和理论,是否有实际学习的免费资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆