<commit_before>(in-package :rtg-math.matrix4)

;;----------------------------------------------------------------

(defn identity () mat4
  "Return a 4x4 identity matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make-array 16 :element-type 'single-float
              :initial-contents '(1f0 0f0 0f0 0f0
                                  0f0 1f0 0f0 0f0
                                  0f0 0f0 1f0 0f0
                                  0f0 0f0 0f0 1f0)))

(defn-inline 0! () mat4
  "Return a 4x4 zero matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make-array 16 :element-type 'single-float :initial-element 0f0))

;;----------------------------------------------------------------

(defn make ((a single-float) (b single-float) (c single-float) (d single-float)
            (e single-float) (f single-float) (g single-float) (h single-float)
            (i single-float) (j single-float) (k single-float) (l single-float)
            (m single-float) (n single-float) (o single-float) (p single-float)) mat4
  "Make a 4x4 matrix. Data must be provided in row major order"
  (declare (optimize (speed 3) (safety 1) (debug 1))
           (inline m4-n:set-components 0!))
  ;; as you can see it is stored in column major order
  (m4-n:set-components a b c d e f g h i j k l m n o p (0!)))

;;----------------------------------------------------------------

(defn-inline copy-mat4 ((mat4 mat4)) mat4
  (declare (optimize (speed 3) (safety 0) (debug 1)))
  (let ((result (make-array 16 :element-type 'single-float)))
    (dotimes (i 16)
      (setf (aref result i) (aref mat4 i)))
    result))

;;----------------------------------------------------------------

(defn to-mat3 ((mat4 mat4)) mat3
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (m3:make (melm mat4 0 0) (melm mat4 0 1) (melm mat4 0 2)
           (melm mat4 1 0) (melm mat4 1 1) (melm mat4 1 2)
           (melm mat4 2 0) (melm mat4 2 1) (melm mat4 2 2)))

;;----------------------------------------------------------------

(defn from-mat3 ((m-a mat3)) mat4
  "Takes a 3x3 matrix and returns a 4x4 rotation matrix
   with the same values. The 4th component is filled as an
   identity matrix would be."
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (m3:melm m-a 0 0)  (m3:melm m-a 0 1)  (m3:melm m-a 0 2)  0f0
        (m3:melm m-a 1 0)  (m3:melm m-a 1 1)  (m3:melm m-a 1 2)  0f0
        (m3:melm m-a 2 0)  (m3:melm m-a 2 1)  (m3:melm m-a 2 2)  0f0
        0f0                0f0                0f0                1f0))

;;----------------------------------------------------------------

(defn from-rows ((row-1 vec4) (row-2 vec4) (row-3 vec4) (row-4 vec4)) mat4
  "Make a 4x4 matrix using the data in the 4 vector4s provided
   to populate the rows"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x row-1) (y row-1) (z row-1) (w row-1)
        (x row-2) (y row-2) (z row-2) (w row-2)
        (x row-3) (y row-3) (z row-3) (w row-3)
        (x row-4) (y row-4) (z row-4) (w row-4)))

(defn from-rows-v3 ((row-1 vec3) (row-2 vec3) (row-3 vec3)) mat4
  "Make a 4x4 matrix using the data in the 4 vector4s provided
   to populate the rows"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x row-1) (y row-1) (z row-1) 0s0
        (x row-2) (y row-2) (z row-2) 0s0
        (x row-3) (y row-3) (z row-3) 0s0
        0s0       0s0       0s0       1s0))

;;----------------------------------------------------------------

(defn get-rows ((mat-a mat4)) list
  "Return the rows of the matrix as 4 vector4s"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (list (v! (melm mat-a 0 0)
            (melm mat-a 0 1)
            (melm mat-a 0 2)
            (melm mat-a 0 3))
        (v! (melm mat-a 1 0)
            (melm mat-a 1 1)
            (melm mat-a 1 2)
            (melm mat-a 1 3))
        (v! (melm mat-a 2 0)
            (melm mat-a 2 1)
            (melm mat-a 2 2)
            (melm mat-a 2 3))
        (v! (melm mat-a 3 0)
            (melm mat-a 3 1)
            (melm mat-a 3 2)
            (melm mat-a 3 3))))

;;----------------------------------------------------------------

(defn get-row ((mat-a mat4) (row-num (integer 0 3))) vec4
  "Return the specified row of the matrix a vector4"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (v4:make (melm mat-a row-num 0)
           (melm mat-a row-num 1)
           (melm mat-a row-num 2)
           (melm mat-a row-num 3)))


;;----------------------------------------------------------------

(defn from-columns ((col-1 vec4) (col-2 vec4) (col-3 vec4) (col-4 vec4)) mat4
  "Make a 4x4 matrix using the data in the 4 vector4s provided
   to populate the columns"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x col-1)
        (x col-2)
        (x col-3)
        (x col-4)
        (y col-1)
        (y col-2)
        (y col-3)
        (y col-4)
        (z col-1)
        (z col-2)
        (z col-3)
        (z col-4)
        (w col-1)
        (w col-2)
        (w col-3)
        (w col-4)))

(defn from-columns-v3 ((col-1 vec3) (col-2 vec3) (col-3 vec3)) mat4
  "Make a 4x4 matrix using the data in the 3 vector3s provided
   to populate the columns"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x col-1)
        (x col-2)
        (x col-3)
        0s0
        (y col-1)
        (y col-2)
        (y col-3)
        0s0
        (z col-1)
        (z col-2)
        (z col-3)
        0s0
        0s0
        0s0
        0s0
        1s0))

;;----------------------------------------------------------------

(defn get-columns ((mat-a mat4)) list
  "Return the columns of the matrix as 4 vector4s"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (list (v! (melm mat-a 0 0)
            (melm mat-a 1 0)
            (melm mat-a 2 0)
            (melm mat-a 3 0))
        (v! (melm mat-a 0 1)
            (melm mat-a 1 1)
            (melm mat-a 2 1)
            (melm mat-a 3 1))
        (v! (melm mat-a 0 2)
            (melm mat-a 1 2)
            (melm mat-a 2 2)
            (melm mat-a 3 2))
        (v! (melm mat-a 0 3)
            (melm mat-a 1 3)
            (melm mat-a 2 3)
            (melm mat-a 3 3))))

;;----------------------------------------------------------------

(defn get-column ((mat-a mat4) (col-num (integer 0 3))) vec4
  "Return the specified column of the matrix a vector4"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (v4:make (melm mat-a 0 col-num)
           (melm mat-a 1 col-num)
           (melm mat-a 2 col-num)
           (melm mat-a 3 col-num)))

;;----------------------------------------------------------------

(defn 0p ((mat-a mat4)) boolean
  "Returns 't' if this is a zero matrix (as contents of the
   matrix are floats the values have an error bound as defined
   in base-maths"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (loop :for i :below 16 :always (cl:= 0f0 (aref mat-a i))))

;;----------------------------------------------------------------

(defn identityp ((mat-a mat4)) boolean
  "Returns 't' if this is an identity matrix (as contents of the
   matrix are floats the values have an error bound as defined
   in base-maths"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (and (cl:= 0f0 (cl:- (melm mat-a 0 0) 1f0))
       (cl:= 0f0 (cl:- (melm mat-a 1 1) 1f0))
       (cl:= 0f0 (cl:- (melm mat-a 2 2) 1f0))
       (cl:= 0f0 (cl:- (melm mat-a 3 3) 1f0))
       (cl:= 0f0 (melm mat-a 0 1))
       (cl:= 0f0 (melm mat-a 0 2))
       (cl:= 0f0 (melm mat-a 0 3))
       (cl:= 0f0 (melm mat-a 1 0))
       (cl:= 0f0 (melm mat-a 1 2))
       (cl:= 0f0 (melm mat-a 1 3))
       (cl:= 0f0 (melm mat-a 2 0))
       (cl:= 0f0 (melm mat-a 2 1))
       (cl:= 0f0 (melm mat-a 2 3))
       (cl:= 0f0 (melm mat-a 3 0))
       (cl:= 0f0 (melm mat-a 3 1))
       (cl:= 0f0 (melm mat-a 3 2))))

;;----------------------------------------------------------------

(defn = ((mat-a mat4) (mat-b mat4)) boolean
  "Returns t if all elements of both matrices provided are
   equal"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (loop :for i :below 16 :always (cl:= (aref mat-a i) (aref mat-b i))))

;;----------------------------------------------------------------

(defn adjoint ((mat-a mat4)) mat4
  "Returns the adjoint of the matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (minor mat-a 1 2 3 1 2 3)
        (cl:- (minor mat-a 0 2 3 1 2 3))
        (minor mat-a 0 1 3 1 2 3)
        (cl:- (minor mat-a 0 1 2 1 2 3))

        (cl:- (minor mat-a 1 2 3 0 2 3))
        (minor mat-a 0 2 3 0 2 3)
        (cl:- (minor mat-a 0 1 3 0 2 3))
        (minor mat-a 0 1 2 0 2 3)

        (minor mat-a 1 2 3 0 1 3)
        (cl:- (minor mat-a 0 2 3 0 1 3))
        (minor mat-a 0 1 3 0 1 3)
        (cl:- (minor mat-a 0 1 2 0 1 3))

        (cl:- (minor mat-a 1 2 3 0 1 2))
        (minor mat-a 0 2 3 0 1 2)
        (cl:- (minor mat-a 0 1 3 0 1 2))
        (minor mat-a 0 1 2 0 1 2)))

;;----------------------------------------------------------------

(defn determinant ((mat-a mat4)) single-float
  "Returns the determinant of the matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (cl:+ (cl:* (melm mat-a 0 0) (minor mat-a 1 2 3 1 2 3))
        (cl:- (cl:* (melm mat-a 0 1) (minor mat-a 1 2 3 0 2 3)))
        (cl:* (melm mat-a 0 2) (minor mat-a 1 2 3 0 1 3))
        (cl:- (cl:* (melm mat-a 0 3) (minor mat-a 1 2 3 0 1 2)))))

;;----------------------------------------------------------------

(defn inverse ((matrix mat4)) mat4
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (let ((det (m4:determinant matrix)))
    (if (cl:= det 0s0)
        (error "Cannot invert matrix with zero determinant:~%  ~S"
               matrix)
        (macrolet ((a (x y z)<commit_msg>ecl crashes on optimizing m4:inverse<commit_after>(in-package :rtg-math.matrix4)

;;----------------------------------------------------------------

(defn identity () mat4
  "Return a 4x4 identity matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make-array 16 :element-type 'single-float
              :initial-contents '(1f0 0f0 0f0 0f0
                                  0f0 1f0 0f0 0f0
                                  0f0 0f0 1f0 0f0
                                  0f0 0f0 0f0 1f0)))

(defn-inline 0! () mat4
  "Return a 4x4 zero matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make-array 16 :element-type 'single-float :initial-element 0f0))

;;----------------------------------------------------------------

(defn make ((a single-float) (b single-float) (c single-float) (d single-float)
            (e single-float) (f single-float) (g single-float) (h single-float)
            (i single-float) (j single-float) (k single-float) (l single-float)
            (m single-float) (n single-float) (o single-float) (p single-float)) mat4
  "Make a 4x4 matrix. Data must be provided in row major order"
  (declare (optimize (speed 3) (safety 1) (debug 1))
           (inline m4-n:set-components 0!))
  ;; as you can see it is stored in column major order
  (m4-n:set-components a b c d e f g h i j k l m n o p (0!)))

;;----------------------------------------------------------------

(defn-inline copy-mat4 ((mat4 mat4)) mat4
  (declare (optimize (speed 3) (safety 0) (debug 1)))
  (let ((result (make-array 16 :element-type 'single-float)))
    (dotimes (i 16)
      (setf (aref result i) (aref mat4 i)))
    result))

;;----------------------------------------------------------------

(defn to-mat3 ((mat4 mat4)) mat3
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (m3:make (melm mat4 0 0) (melm mat4 0 1) (melm mat4 0 2)
           (melm mat4 1 0) (melm mat4 1 1) (melm mat4 1 2)
           (melm mat4 2 0) (melm mat4 2 1) (melm mat4 2 2)))

;;----------------------------------------------------------------

(defn from-mat3 ((m-a mat3)) mat4
  "Takes a 3x3 matrix and returns a 4x4 rotation matrix
   with the same values. The 4th component is filled as an
   identity matrix would be."
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (m3:melm m-a 0 0)  (m3:melm m-a 0 1)  (m3:melm m-a 0 2)  0f0
        (m3:melm m-a 1 0)  (m3:melm m-a 1 1)  (m3:melm m-a 1 2)  0f0
        (m3:melm m-a 2 0)  (m3:melm m-a 2 1)  (m3:melm m-a 2 2)  0f0
        0f0                0f0                0f0                1f0))

;;----------------------------------------------------------------

(defn from-rows ((row-1 vec4) (row-2 vec4) (row-3 vec4) (row-4 vec4)) mat4
  "Make a 4x4 matrix using the data in the 4 vector4s provided
   to populate the rows"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x row-1) (y row-1) (z row-1) (w row-1)
        (x row-2) (y row-2) (z row-2) (w row-2)
        (x row-3) (y row-3) (z row-3) (w row-3)
        (x row-4) (y row-4) (z row-4) (w row-4)))

(defn from-rows-v3 ((row-1 vec3) (row-2 vec3) (row-3 vec3)) mat4
  "Make a 4x4 matrix using the data in the 4 vector4s provided
   to populate the rows"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x row-1) (y row-1) (z row-1) 0s0
        (x row-2) (y row-2) (z row-2) 0s0
        (x row-3) (y row-3) (z row-3) 0s0
        0s0       0s0       0s0       1s0))

;;----------------------------------------------------------------

(defn get-rows ((mat-a mat4)) list
  "Return the rows of the matrix as 4 vector4s"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (list (v! (melm mat-a 0 0)
            (melm mat-a 0 1)
            (melm mat-a 0 2)
            (melm mat-a 0 3))
        (v! (melm mat-a 1 0)
            (melm mat-a 1 1)
            (melm mat-a 1 2)
            (melm mat-a 1 3))
        (v! (melm mat-a 2 0)
            (melm mat-a 2 1)
            (melm mat-a 2 2)
            (melm mat-a 2 3))
        (v! (melm mat-a 3 0)
            (melm mat-a 3 1)
            (melm mat-a 3 2)
            (melm mat-a 3 3))))

;;----------------------------------------------------------------

(defn get-row ((mat-a mat4) (row-num (integer 0 3))) vec4
  "Return the specified row of the matrix a vector4"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (v4:make (melm mat-a row-num 0)
           (melm mat-a row-num 1)
           (melm mat-a row-num 2)
           (melm mat-a row-num 3)))


;;----------------------------------------------------------------

(defn from-columns ((col-1 vec4) (col-2 vec4) (col-3 vec4) (col-4 vec4)) mat4
  "Make a 4x4 matrix using the data in the 4 vector4s provided
   to populate the columns"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x col-1)
        (x col-2)
        (x col-3)
        (x col-4)
        (y col-1)
        (y col-2)
        (y col-3)
        (y col-4)
        (z col-1)
        (z col-2)
        (z col-3)
        (z col-4)
        (w col-1)
        (w col-2)
        (w col-3)
        (w col-4)))

(defn from-columns-v3 ((col-1 vec3) (col-2 vec3) (col-3 vec3)) mat4
  "Make a 4x4 matrix using the data in the 3 vector3s provided
   to populate the columns"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (x col-1)
        (x col-2)
        (x col-3)
        0s0
        (y col-1)
        (y col-2)
        (y col-3)
        0s0
        (z col-1)
        (z col-2)
        (z col-3)
        0s0
        0s0
        0s0
        0s0
        1s0))

;;----------------------------------------------------------------

(defn get-columns ((mat-a mat4)) list
  "Return the columns of the matrix as 4 vector4s"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (list (v! (melm mat-a 0 0)
            (melm mat-a 1 0)
            (melm mat-a 2 0)
            (melm mat-a 3 0))
        (v! (melm mat-a 0 1)
            (melm mat-a 1 1)
            (melm mat-a 2 1)
            (melm mat-a 3 1))
        (v! (melm mat-a 0 2)
            (melm mat-a 1 2)
            (melm mat-a 2 2)
            (melm mat-a 3 2))
        (v! (melm mat-a 0 3)
            (melm mat-a 1 3)
            (melm mat-a 2 3)
            (melm mat-a 3 3))))

;;----------------------------------------------------------------

(defn get-column ((mat-a mat4) (col-num (integer 0 3))) vec4
  "Return the specified column of the matrix a vector4"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (v4:make (melm mat-a 0 col-num)
           (melm mat-a 1 col-num)
           (melm mat-a 2 col-num)
           (melm mat-a 3 col-num)))

;;----------------------------------------------------------------

(defn 0p ((mat-a mat4)) boolean
  "Returns 't' if this is a zero matrix (as contents of the
   matrix are floats the values have an error bound as defined
   in base-maths"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (loop :for i :below 16 :always (cl:= 0f0 (aref mat-a i))))

;;----------------------------------------------------------------

(defn identityp ((mat-a mat4)) boolean
  "Returns 't' if this is an identity matrix (as contents of the
   matrix are floats the values have an error bound as defined
   in base-maths"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (and (cl:= 0f0 (cl:- (melm mat-a 0 0) 1f0))
       (cl:= 0f0 (cl:- (melm mat-a 1 1) 1f0))
       (cl:= 0f0 (cl:- (melm mat-a 2 2) 1f0))
       (cl:= 0f0 (cl:- (melm mat-a 3 3) 1f0))
       (cl:= 0f0 (melm mat-a 0 1))
       (cl:= 0f0 (melm mat-a 0 2))
       (cl:= 0f0 (melm mat-a 0 3))
       (cl:= 0f0 (melm mat-a 1 0))
       (cl:= 0f0 (melm mat-a 1 2))
       (cl:= 0f0 (melm mat-a 1 3))
       (cl:= 0f0 (melm mat-a 2 0))
       (cl:= 0f0 (melm mat-a 2 1))
       (cl:= 0f0 (melm mat-a 2 3))
       (cl:= 0f0 (melm mat-a 3 0))
       (cl:= 0f0 (melm mat-a 3 1))
       (cl:= 0f0 (melm mat-a 3 2))))

;;----------------------------------------------------------------

(defn = ((mat-a mat4) (mat-b mat4)) boolean
  "Returns t if all elements of both matrices provided are
   equal"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (loop :for i :below 16 :always (cl:= (aref mat-a i) (aref mat-b i))))

;;----------------------------------------------------------------

(defn adjoint ((mat-a mat4)) mat4
  "Returns the adjoint of the matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (make (minor mat-a 1 2 3 1 2 3)
        (cl:- (minor mat-a 0 2 3 1 2 3))
        (minor mat-a 0 1 3 1 2 3)
        (cl:- (minor mat-a 0 1 2 1 2 3))

        (cl:- (minor mat-a 1 2 3 0 2 3))
        (minor mat-a 0 2 3 0 2 3)
        (cl:- (minor mat-a 0 1 3 0 2 3))
        (minor mat-a 0 1 2 0 2 3)

        (minor mat-a 1 2 3 0 1 3)
        (cl:- (minor mat-a 0 2 3 0 1 3))
        (minor mat-a 0 1 3 0 1 3)
        (cl:- (minor mat-a 0 1 2 0 1 3))

        (cl:- (minor mat-a 1 2 3 0 1 2))
        (minor mat-a 0 2 3 0 1 2)
        (cl:- (minor mat-a 0 1 3 0 1 2))
        (minor mat-a 0 1 2 0 1 2)))

;;----------------------------------------------------------------

(defn determinant ((mat-a mat4)) single-float
  "Returns the determinant of the matrix"
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (cl:+ (cl:* (melm mat-a 0 0) (minor mat-a 1 2 3 1 2 3))
        (cl:- (cl:* (melm mat-a 0 1) (minor mat-a 1 2 3 0 2 3)))
        (cl:* (melm mat-a 0 2) (minor mat-a 1 2 3 0 1 3))
        (cl:- (cl:* (melm mat-a 0 3) (minor mat-a 1 2 3 0 1 2)))))

;;----------------------------------------------------------------

(defn inverse ((matrix mat4)) mat4
  ;;(declare (optimize (speed 3) (safety 1) (debug 1)))
  (let ((det (m4:determinant matrix)))
    (if (cl:= det 0s0)
        (error "Cannot invert matrix with zero determinant:~%  ~S"
               matrix)
        (macrolet ((a (x y z)
{'fraction_non_alphanumeric': 0.24293843235761522, 'fraction_numerical': 0.06566873430050751, 'mean_word_length': 1.3540485097140098, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4096040', 'n_tokens_mistral': 8058, 'n_tokens_neox': 7043, 'n_words': 2659}