From: Akshay S. <ak...@us...> - 2012-07-04 11:10:35
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "matlisp". The branch, tensor has been updated via d8e8b94a89920c6c741031b0a525fec2c62a9d2d (commit) via 3727a088ffe014773472fd37a7d45346917a73a0 (commit) from 695636685fd91ce1602b135d0c0e782ca06d47e7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d8e8b94a89920c6c741031b0a525fec2c62a9d2d Author: Akshay Srinivasan <aks...@gm...> Date: Wed Jul 4 16:36:01 2012 +0530 Cleaned up permutation.lisp diff --git a/matlisp.asd b/matlisp.asd index e300c13..cbdbae3 100644 --- a/matlisp.asd +++ b/matlisp.asd @@ -93,6 +93,8 @@ :depends-on ("standard-tensor")) (:file "blas-helpers" :depends-on ("standard-tensor")) + (:file "permutation" + :depends-on ("standard-tensor")) ;; (:file "real-tensor" :depends-on ("standard-tensor")) diff --git a/src/conditions.lisp b/src/conditions.lisp index ad16f1e..27986e0 100644 --- a/src/conditions.lisp +++ b/src/conditions.lisp @@ -13,78 +13,86 @@ (in-package :matlisp) -;;---------------------------------------------------------------;; -(define-condition generic-error (error) - ((message :reader message :initarg :message :initform ""))) - -(defmethod print-object ((c generic-error) stream) - (format stream (message c))) - -;;---------------------------------------------------------------;; -(define-condition invalid-type (generic-error) +(defmacro defcondition (name (&rest parent-types) (&rest slot-specs) &body options) + "Like define-condition except that you can define + methods inside the condition definition with: + (:method {generic-function-name} {args*} &rest code*) +" + (labels ((get-methods (opts mth rst) + (if (null opts) (values (reverse mth) (reverse rst)) + (if (and (consp (car opts)) (eq (caar opts) :method)) + (get-methods (cdr opts) (cons (car opts) mth) rst) + (get-methods (cdr opts) mth (cons (car opts) rst)))))) + (multiple-value-bind (methods rest) (get-methods options nil nil) + `(progn + (define-condition ,name ,parent-types + ,slot-specs + ,@rest) + ,@(loop for mth in methods + collect `(defmethod ,@(cdr mth))))))) +;;Generic conditions---------------------------------------------;; +(defcondition generic-error (error) + ((message :reader message :initarg :message :initform "")) + (:method print-method ((c generic-error) stream) + (format stream (message c)))) + +(defcondition invalid-type (generic-error) ((given-type :reader given :initarg :given) (expected-type :reader expected :initarg :expected)) - (:documentation "Given an unexpected type.")) - -(defmethod print-object ((c invalid-type) stream) - (format stream "Given object of type ~A, expected ~A.~%" (given c) (expected c)) - (call-next-method)) + (:documentation "Given an unexpected type.") + (:method print-object ((c invalid-type) stream) + (format stream "Given object of type ~A, expected ~A.~%" (given c) (expected c)) + (call-next-method))) -;;---------------------------------------------------------------;; -(define-condition invalid-value (generic-error) +(defcondition invalid-value (generic-error) ((given-value :reader given :initarg :given) (expected-value :reader expected :initarg :expected)) - (:documentation "Given an unexpected value.")) + (:documentation "Given an unexpected value.") + (:method print-object ((c invalid-value) stream) + (format stream "Given object ~A, expected ~A.~%" (given c) (expected c)) + (call-next-method))) -(defmethod print-object ((c invalid-value) stream) - (format stream "Given object ~A, expected ~A.~%" (given c) (expected c)) - (call-next-method)) - -;;---------------------------------------------------------------;; -(define-condition unknown-token (generic-error) +(defcondition unknown-token (generic-error) ((token :reader token :initarg :token)) - (:documentation "Given an unknown token.")) - -(defmethod print-object ((c unknown-token) stream) - (format stream "Given unknown token: ~A.~%" (token c)) - (call-next-method)) + (:documentation "Given an unknown token.") + (:method print-object ((c unknown-token) stream) + (format stream "Given unknown token: ~A.~%" (token c)) + (call-next-method))) -;;---------------------------------------------------------------;; -(define-condition coercion-error (generic-error) +(defcondition coercion-error (generic-error) ((from :reader from :initarg :from) (to :reader to :initarg :to)) - (:documentation "Cannot coerce one type into another.")) - -(defmethod print-object ((c coercion-error) stream) - (format stream "Cannot coerce ~a into ~a." (from c) (to c)) - (call-next-method)) + (:documentation "Cannot coerce one type into another.") + (:method print-object ((c coercion-error) stream) + (format stream "Cannot coerce ~a into ~a." (from c) (to c)) + (call-next-method))) -;;---------------------------------------------------------------;; -(define-condition matlisp-error (error) +;;Tensor conditions----------------------------------------------;; +(define-condition tensor-error (error) ;;Optional argument for error-handling. ((tensor :reader tensor :initarg :tensor))) -(define-condition store-index-out-of-bounds (matlisp-error) +(define-condition tensor-store-index-out-of-bounds (tensor-error) ((index :reader index :initarg :index) (store-size :reader store-size :initarg :store-size)) (:documentation "An out of bounds index error for the one-dimensional store.") (:report (lambda (c stream) (format stream "Requested index ~A, but store is only of size ~A." (index c) (store-size c))))) -(define-condition tensor-not-matrix (matlisp-error) - ((tensor-rank :reader rank :initarg :rank)) - (:documentation "Given tensor is not a matrix.") - (:report (lambda (c stream) - (format stream "Given tensor with rank ~A, is not a matrix." (rank c))))) - -(define-condition insufficient-store (matlisp-error) +(define-condition tensor-insufficient-store (tensor-error) ((store-size :reader store-size :initarg :store-size) (max-idx :reader max-idx :initarg :max-idx)) (:documentation "Store is too small for the tensor with given dimensions.") (:report (lambda (c stream) (format stream "Store size is ~A, but maximum possible index is ~A." (store-size c) (max-idx c))))) -(define-condition tensor-index-out-of-bounds (matlisp-error) +(define-condition tensor-not-matrix (tensor-error) + ((tensor-rank :reader rank :initarg :rank)) + (:documentation "Given tensor is not a matrix.") + (:report (lambda (c stream) + (format stream "Given tensor with rank ~A, is not a matrix." (rank c))))) + +(define-condition tensor-index-out-of-bounds (tensor-error) ((argument :reader argument :initarg :argument) (index :reader index :initarg :index) (argument-space-dimension :reader dimension :initarg :dimension)) @@ -92,48 +100,68 @@ (:report (lambda (c stream) (format stream "~&Out of bounds for argument ~A: requested ~A, but dimension is only ~A." (argument c) (index c) (dimension c))))) -(define-condition tensor-index-rank-mismatch (matlisp-error) +(define-condition tensor-index-rank-mismatch (tensor-error) ((index-rank :reader index-rank :initarg :index-rank) (rank :reader rank :initarg :rank)) (:documentation "Incorrect number of subscripts for the tensor.") (:report (lambda (c stream) (format stream "Index is of size ~A, whereas the tensor is of rank ~A." (index-rank c) (rank c))))) -(define-condition tensor-invalid-head-value (matlisp-error) +(define-condition tensor-invalid-head-value (tensor-error) ((head :reader head :initarg :head)) (:documentation "Incorrect value for the head of the tensor storage.") (:report (lambda (c stream) (format stream "Head of the store must be >= 0, initialized with ~A." (head c))))) -(define-condition tensor-invalid-dimension-value (matlisp-error) +(define-condition tensor-invalid-dimension-value (tensor-error) ((argument :reader argument :initarg :argument) (argument-dimension :reader dimension :initarg :dimension)) (:documentation "Incorrect value for one of the dimensions of the tensor.") (:report (lambda (c stream) (format stream "Dimension of argument ~A must be > 0, initialized with ~A." (argument c) (dimension c))))) -(define-condition tensor-invalid-stride-value (matlisp-error) +(define-condition tensor-invalid-stride-value (tensor-error) ((argument :reader argument :initarg :argument) (argument-stride :reader stride :initarg :stride)) (:documentation "Incorrect value for one of the strides of the tensor storage.") (:report (lambda (c stream) (format stream "Stride of argument ~A must be >= 0, initialized with ~A." (argument c) (stride c))))) -(define-condition tensor-cannot-find-sub-class (matlisp-error) +(define-condition tensor-cannot-find-sub-class (tensor-error) ((tensor-class :reader tensor-class :initarg :tensor-class)) (:documentation "Cannot find sub-class of the given tensor class") (:report (lambda (c stream) (format stream "Cannot find sub-class of the given tensor class: ~a." (tensor-class c))))) -(define-condition tensor-cannot-find-optimization (matlisp-error) +(define-condition tensor-cannot-find-optimization (tensor-error) ((tensor-class :reader tensor-class :initarg :tensor-class)) (:documentation "Cannot find optimization information for the given tensor class") (:report (lambda (c stream) (format stream "Cannot find optimization information for the given tensor class: ~a." (tensor-class c))))) -(define-condition tensor-dimension-mismatch (matlisp-error) +(define-condition tensor-dimension-mismatch (tensor-error) () (:documentation "The dimensions of the given tensors are not suitable for continuing with the operation.") (:report (lambda (c stream) (declare (ignore c)) (format stream "The dimensions of the given tensors are not suitable for continuing with the operation.")))) + +;;Permutation conditions-----------------------------------------;; +(define-condition permutation-error (error) + ((permutation :reader permutation :initarg :permutation))) + +(define-condition permutation-invalid-error (permutation-error) + () + (:documentation "Object is not a permutation.") + (:report (lambda (c stream) + (declare (ignore c)) + (format stream "Object is not a permutation.")))) + +(define-condition permutation-permute-error (permutation-error) + ((sequence-length :reader seq-len :initarg :seq-len) + (group-rank :reader group-rank :initarg :group-rank)) + (:documentation "Cannot permute sequence.") + (:report (lambda (c stream) + (format stream "Cannot permute sequence. +sequence-length : ~a +group-rank: ~a" (seq-len c) (group-rank c))))) diff --git a/src/loopy-tests.lisp b/src/loopy-tests.lisp index fbaafe0..8998588 100644 --- a/src/loopy-tests.lisp +++ b/src/loopy-tests.lisp @@ -44,7 +44,7 @@ do (setf (aref st-a of-a) (random 1d0) (aref st-b of-b) (random 1d0) (aref st-c of-c) 0d0))) - (time + (time (very-quickly (mod-dotimes (idx (idxv n n n)) with (loop-order :row-major) @@ -52,7 +52,7 @@ (of-a (idxv n 1 0)) (of-b (idxv 0 n 1)) (of-c (idxv n 0 1))) - do (incf (aref st-c of-c) (* (aref st-a of-a) (aref st-b of-b))))))))) + do (incf (aref st-c of-c) (* (aref st-a of-a) (aref st-b of-b))))))))) (defun test-mm-ddot (n) (let* ((t-a (make-real-tensor-dims n n)) diff --git a/src/permutation.lisp b/src/permutation.lisp new file mode 100644 index 0000000..40e0af2 --- /dev/null +++ b/src/permutation.lisp @@ -0,0 +1,317 @@ +(in-package :matlisp) + +(defun id-action-repr (n) + (declare (type fixnum n)) + (let ((ret (allocate-index-store n))) + (declare (type (index-array *) ret)) + (very-quickly + (loop + for i of-type index-type from 0 below n + do (setf (aref ret i) i))) + ret)) + +(defun seqrnd (seq) + "Randomize the elements of a sequence. Destructive on SEQ." + (sort seq #'> :key #'(lambda (x) (random 1.0)))) + +;;Class definitions----------------------------------------------;; +(defclass permutation () + ((representation :accessor repr + :initarg :repr) + (group-rank :accessor group-rank + :type index-type))) + +(defparameter +permutation-identity+ + (let ((ret (make-instance 'permutation :repr :id))) + (setf (group-rank ret) 0) + ret)) + +(defmethod print-object ((per permutation) stream) + (print-unreadable-object (per stream :type t) + (format stream "S_~a~%~a~%" (group-rank per) (repr per)))) +;; +(defclass permutation-cycle (permutation) + ((representation :type cons))) + +(defun cycle-repr-p (perm) + " + Does a sorting operation to check for duplicate elements in + the cycle representation of a permutation. +" + (if (not (typep perm '(index-array *))) nil + (locally + (declare (type (index-array *) perm)) + (let ((len (length perm))) + (declare (type index-type len)) + (if (<= len 1) nil + (let ((sort (very-quickly (sort (copy-seq perm) #'<)))) + (declare (type (index-array *) sort)) + (very-quickly + (loop for i of-type index-type from 1 below len + when (= (aref sort i) (aref sort (1- i))) + do (return nil) + finally (return t))))))))) + +(defmethod initialize-instance :after ((per permutation-cycle) &rest initargs) + (declare (ignore initargs)) + (very-quickly + (loop + for cyc of-type (index-array *) in (repr per) + unless (cycle-repr-p cyc) + do (error 'permutation-invalid-error) + maximizing (idx-max cyc) into g-rnk of-type index-type + finally (setf (group-rank per) (the index-type (1+ g-rnk)))))) + +(definline make-pcycle (&rest args) + (make-instance 'permutation-cycle :repr args)) + +;; +(defclass permutation-action (permutation) + ((representation :type (index-array *)))) + +(defun action-repr-p (act) + " + Checks if ARR is a possible permutation vector. A permutation pi + is characterized by a vector containing the indices from 0,..., + @function{length}(@arg{perm})-1 in some order. +" + (if (not (typep act '(index-array *))) nil + (locally + (declare (type (index-array *) act)) + (let* ((len (length act)) + (sort (very-quickly (sort (copy-seq act) #'<)))) + (declare (type (index-array *) sort) + (type index-type len)) + (very-quickly + (loop for i of-type index-type from 0 below len + unless (= (aref sort i) i) + do (return nil) + finally (return t))))))) + +(defmethod initialize-instance :after ((per permutation-action) &rest initargs) + (declare (ignore initargs)) + (let ((act (repr per))) + (declare (type (index-array *) act)) + (unless (action-repr-p act) + (error 'permutation-invalid-error)) + (setf (group-rank per) (1+ (idx-max act))))) + +(definline make-paction (pact) + (make-instance 'permutation-action :repr pact)) + +;;Conversions and validation-------------------------------------;; +(defun action->cycle (act) + " + (action->cycle act) + + This function obtains the canonical cycle representation + of a permutation. The first argument \"act\" is the action of the + permutation on the array #(0 1 2 3 ..): an object of the class + permutation-action. + + \"Canonical\" may be a bit of an overstatement; this is the way + S_n was presented in Van der Waerden's book. +" + (declare (type permutation-action act)) + (mlet* + ((arr (repr act) :type (index-array *))) + (labels ((find-cycle (x0) + ;; This function obtains the cycle starting from x_0. + (declare (type index-type x0)) + (if (= (aref arr x0) x0) (values 0 nil) + (very-quickly + (loop + for x of-type index-type = (aref arr x0) then (aref arr x) + and ret of-type cons = (list x0) then (cons x ret) + counting t into i of-type index-type + when (= x x0) + do (return (values i ret)))))) + (cycle-walk (cyc ignore) + ;; Finds all cycles + (let ((x0 (find-if-not #'(lambda (x) (member x ignore)) arr))) + (if (null x0) + cyc + (multiple-value-bind (clen clst) (find-cycle x0) + (declare (type index-type clen) + (type list clst)) + (cycle-walk + (if (= clen 0) cyc + (cons (make-array clen :element-type 'index-type :initial-contents clst) cyc)) + (nconc ignore (if (= clen 0) (list x0) clst)))))))) + (let ((cyc-lst (cycle-walk nil nil))) + (if (null cyc-lst) + +permutation-identity+ + (make-instance 'permutation-cycle + :repr cyc-lst)))))) + +(defun cycle->action (cyc) + " + (cycle->action cyc) + + This function obtains the action representation of a permutation + from the cyclic one. The first argument \"cyc\" is the cyclic + representation of the permutation: an object of the class + permutation-cycle. +" + (declare (type permutation-cycle cyc)) + (let ((act-repr (id-action-repr (group-rank cyc))) + (cycs-repr (repr cyc))) + (declare (type (index-array *) act-repr)) + (dolist (cyc cycs-repr) + (declare (type (index-array *) cyc)) + (let ((xl (aref act-repr (aref cyc (1- (length cyc)))))) + (very-quickly + (loop + for i of-type index-type downfrom (1- (length cyc)) to 0 + do (setf (aref act-repr (aref cyc i)) + (if (= i 0) xl + (aref act-repr (aref cyc (1- i))))))))) + (make-instance 'permutation-action :repr act-repr))) + +;; +(defgeneric permute! (seq perm) + (:documentation " + (permute! seq perm) + + Applies the permutation on the sequence. +") + (:method ((seq sequence) (perm (eql +permutation-identity+))) + seq)) + +(defmethod permute! ((seq sequence) (perm permutation-cycle)) + (labels ((apply-cycle! (seq pcyc) + (declare (type (index-array *) pcyc)) + (very-quickly + (let ((xl (aref seq (aref pcyc (1- (length pcyc)))))) + (loop for i of-type index-type downfrom (1- (length pcyc)) to 0 + do (setf (aref seq (aref pcyc i)) + (if (= i 0) xl + (aref seq (aref pcyc (1- i)))))))))) + (let ((len (length seq)) + (glen (group-rank perm)) + (cycs-lst (repr perm))) + (declare (type index-type len glen)) + (if (< len glen) (error 'permutation-permute-error :seq-len len :group-rank glen) + (etypecase seq + (vector + (dolist (cyc cycs-lst seq) + (declare (type (index-array *) cyc)) + (apply-cycle! seq cyc))) + (cons + (let ((cseq (make-array len :initial-contents seq))) + (declare (type (simple-vector *) cseq)) + (dolist (cyc cycs-lst) + (declare (type (index-array *) cyc)) + (apply-cycle! cseq cyc)) + (mapl + (let ((i 0)) + (declare (type fixnum i)) + (lambda (x) + (when (< i glen) + (rplaca x (aref cseq i)) + (incf i)))) + seq)))))))) + +(defmethod permute! ((seq sequence) (perm permutation-action)) + (let ((len (length seq)) + (glen (group-rank perm))) + (declare (type index-type len glen)) + (if (< len glen) (error 'permutation-permute-error :seq-len len :group-rank glen) + (let ((cseq (make-array len :initial-contents seq)) + (act (repr perm))) + (declare (type (simple-vector *) cseq) + (type (index-array *) act)) + (etypecase seq + (vector + (very-quickly + (loop + for i of-type index-type from 0 below glen + do (unless (= i (aref act i)) + (setf (aref seq i) (aref cseq (aref act i)))) + finally (return seq)))) + (cons + (mapl + (let ((i 0)) + (declare (type fixnum i)) + (lambda (x) + (when (< i glen) + (rplaca x (aref cseq (aref act i))) + (incf i)))) + seq))))))) + +(defun permute (seq perm) + (declare (type sequence seq) + (type permutation perm)) + (let ((cseq (copy-seq seq))) + (permute! cseq perm))) +;; +#+nil +(defun permute-argument (func-symbol perm) + (declare (type symbol func-symbol) + (type permutation perm)) + (let* ((glen (group-rank perm)) + (args (loop for i from 0 below glen + collect (gensym)))) + (eval `(lambda (,@args &rest rest) + (apply ',func-symbol (append (list ,@(permute! args perm)) rest)))))) + +(defun argument-permute (func perm) + (declare (type function func) + (type permutation perm)) + (lambda (&rest args) + (apply func (permute! args perm)))) + +(defun curry (func perm &rest curried-args) + (declare (type function func) + (type permutation perm)) + (lambda (&rest args) + (apply func (permute! (append curried-args args) perm)))) + +(defun compose (func-a func-b perm) + (declare (type function func-a func-b) + (type permutation perm)) + (lambda (&rest args) + (apply func-a (permute! (multiple-value-list (funcall func-b args)) perm)))) +;; + +(defun idx-sort-permute (seq predicate) + " + (sort-permute seq predicate) + + Sorts a index-array and also returns + the permutation-action required to move + from the given sequence to the sorted form. + + Takes about 10x the running time which can be + achieved with cl:sort. + " + (declare (type (index-array *) seq) + (type function predicate)) + (let* ((len (length seq)) + (perm (id-action-repr len))) + (declare (type index-type len) + (type (index-array *) perm)) + (labels ((qsort-bounds (lb ub) + (declare (type index-type lb ub)) + #+nil(format t "~a lb:~a ub:~a ~%" seq lb ub) + (if (= ub (1+ lb)) t + (let* ((ele (aref seq lb)) + (ele-idx (very-quickly + (loop + for i of-type index-type from (1+ lb) below ub + with ele-idx of-type index-type = lb + do (unless (funcall predicate ele (aref seq i)) + (when (> i (1+ ele-idx)) + (rotatef (aref seq ele-idx) (aref seq (1+ ele-idx))) + (rotatef (aref perm ele-idx) (aref perm (1+ ele-idx)))) + (rotatef (aref seq ele-idx) (aref seq i)) + (rotatef (aref perm ele-idx) (aref perm i)) + (incf ele-idx) + #+nil(format t " ~a ~%" seq)) + finally (return ele-idx))))) + (when (> (- ub ele-idx) 2) + (qsort-bounds (1+ ele-idx) ub)) + (when (> (- ele-idx lb) 1) + (qsort-bounds lb ele-idx)))))) + (qsort-bounds 0 len) + (values seq (action->cycle (make-paction perm)))))) diff --git a/src/permutations.lisp b/src/permutations.lisp deleted file mode 100644 index c68d97d..0000000 --- a/src/permutations.lisp +++ /dev/null @@ -1,230 +0,0 @@ -(in-package :matlisp) - -(define-condition permutation-error (generic-error) - ((message :reader message :initform "Object is not a permutation.")) - (:documentation "Object is not a permutation.")) - -;;Class definitions----------------------------------------------;; -(defclass permutation () - ((representation :accessor repr - :initarg :repr) - (group-rank :accessor group-rank - :type index-type))) -;; -(defclass permutation-cycle (permutation) - ((representation :type cons))) - -(defmethod initialize-instance :after ((per permutation-cycle) &rest initargs) - (declare (ignore initargs)) - (let ((cls 0)) - (declare (type index-type cls)) - (unless (very-quickly - (dolist (cyc (r-value per) t) - (unless (cycle-p cyc) - (return nil)) - (setf cls (max cls (idx-max cyc))))) - (error 'permutation-error)) - (setf (group-rank per) (the index-type (1+ cls))))) -;; -(defclass permutation-action (permutation) - ((representation :type (index-array *)))) - -(defmethod initialize-instance :after ((per permutation-action) &rest initargs) - (declare (ignore initargs)) - (let ((act (r-value per))) - (declare (type (index-array *) act)) - (unless (action-p act) - (error 'permutation-error)) - (setf (group-rank per) (idx-max act)))) - -;;Conversions and validation-------------------------------------;; -(defun insert-element (x sort l-b u-b) - "Does a binary-esque sort to keep track of elements in - a permutation, in descending order. If there are duplicates - of X in sort between L-B and U-B (both inclusive), or if X < 0, - then throws a PERMUTATION-ERROR." - (declare (type index-type x l-b u-b) - (type (index-array *) sort)) - (let* ((len u-b)) - (labels ((insert-ele (l-b u-b) - (declare (type index-type l-b u-b)) - (let* ((midx (+ l-b (floor (- u-b l-b) 2))) - (mid (aref sort midx))) - (declare (type index-type midx mid)) - (cond - ((or (< x 0) (member x `(,(aref sort u-b) ,(aref sort l-b) ,mid))) - (error 'permutation-error)) - ((= midx l-b) - (when (> x (aref sort u-b)) - (very-quickly - (loop - with sidx of-type index-type = (+ midx (if (> x mid) 0 1)) - for i of-type index-type downfrom (1- len) to sidx - do (setf (aref sort (+ i 1)) (aref sort i)) - finally (setf (aref sort sidx) x))))) - ((< x mid) (insert-ele midx u-b)) - ((> x mid) (insert-ele l-b midx))) - sort))) - (insert-ele l-b u-b)))) - -(defun cycle-new-p (perm) - "Does a sorting operation to check for duplicate elements in - the cycle representation of a permutation." - (declare (type (index-array *) perm)) - (let* ((len (length perm)) - (sort (very-quickly (sort (copy-seq perm) #'<)))) - (declare (type (index-array *) sort) - (type index-type len)) - (very-quickly - (loop for i of-type index-type from 1 below len - when (= (aref sort i) (aref sort (1- i))) - do (return nil) - finally (return t))))) - -(defun action-p (act) - "Checks if ARR is a possible permutation vector. A permutation pi - is characterized by a vector containing the indices from 0,..., - @function{length}(@arg{perm})-1 in some order." - (declare (type (index-array *) act)) - (let* ((len (length act)) - (sort (very-quickly (sort (copy-seq act) #'<)))) - (declare (type (index-array *) sort) - (type index-type len)) - (very-quickly - (loop for i of-type index-type from 0 below len - unless (= (aref sort i) i) - do (return nil) - finally (return t))))) - -(defun action->cycle (act) - ;;Caution: will go into an infinite loop if object is not proper. - " - This function obtains the canonical cycle representation - of a permutation. The first argument is the action of the - permutation on the array #(0 1 2 3 ..). - \"Canonical\" may be a bit of an overstatement; this is the way - S_n was presented by Van der Waerden. -" - (declare (type permutation-action per)) - (mlet* - ((arr (r-value per) :type (index-array *))) - (labels ((find-cycle (arr x0) - "This function obtains a permutation cycle starting from x_0. - The first argument is the action of the permutation on the - array #(0 1 2 ..)" - (declare (type (index-array *) arr) - (type index-type x0)) - (if (= (aref arr x0) x0) (values #() nil) - (destructuring-bind (n lst) - (do ((i 0 (+ i 1)) - (x x0 (aref arr x)) - (ret nil (cons x ret)) - (count 0 (+ count (if (= x x0) 1 0)))) - ((and (= count 1) (= x x0)) (list i ret))) - (values (make-array n :element-type 'index-type :initial-contents lst) lst)))) - (cycle-walk (cyc ignore) - (declare (optimize (speed 3) (safety 0))) - (let ((x0 (find-if-not #'(lambda (x) (member x ignore)) arr))) - (if (null x0) cyc - (multiple-value-bind (cnew clst) (find-cycle arr x0) - (cycle-walk (if (null clst) cyc (cons cnew cyc)) - (nconc ignore (if (null clst) (list x0) clst)))))))) - (cycle-walk nil nil)))) -;;---------------------------------------------------------------;; - - -(defun cycles->action (cyc) - ) - -;; -(defun apply-cycle! (seq cyc) - (declare (type (index-array *) cyc) - (type (vector * *) seq)) - (unless (cycle-p cyc) - (error 'permutation-error)) - (when (> (length cyc) 1) - (let ((xl (aref seq (aref cyc (- (length cyc) 1))))) - (loop for i downfrom (- (length cyc) 1) to 0 - do (setf (aref seq (aref cyc i)) - (if (= i 0) xl - (aref seq (aref cyc (- i 1)))))))) - seq) - -(defun permute! (seq cycs) - (unless (or (null cycs) (= (length seq) 0)) - (dolist (cyc cycs) - (apply-cycle! seq cyc))) - seq) - -(defun arg-perm (func cycs) - (if (null cycs) - func - (lambda (&rest args) - (let ((argvec (permute! (apply #'vector args) cycs))) - (apply func (loop for i from 0 below (length argvec) - collect (aref argvec i))))))) - -(defun compose (func func) - -;; (defun compose (..) -;; ) - -(defun seqrnd (seq) - "Randomize the elements of a sequence. Destructive on SEQ." - (sort seq #'> :key #'(lambda (x) (random 1.0)))) - -;; - -(defun allocate-unit-permutation (n) - (declare (type fixnum n)) - (let ((ret (allocate-index-store n))) - (declare (type (index-array *) ret)) - (very-quickly - (loop - for i of-type index-type from 0 below n - do (setf (aref ret i) i))) - ret)) - -(defun sort-permute (seq predicate) - " - (sort-permute seq predicate) - - Sorts a index-array and also returns - the permutation-action required to move - from the given sequence to the sorted form. - - Takes about 10x the running time which can be - achieved with cl:sort. - " - (declare (type (index-array *) seq) - (type function predicate)) - (let* ((len (length seq)) - (perm (allocate-unit-permutation len))) - (declare (type index-type len) - (type (index-array *) perm)) - (labels ((qsort-bounds (lb ub) - (declare (type index-type lb ub)) - #+nil(format t "~a lb:~a ub:~a ~%" seq lb ub) - (if (= ub (1+ lb)) t - (let* ((ele (aref seq lb)) - (ele-idx (very-quickly - (loop - for i of-type index-type from (1+ lb) below ub - with ele-idx of-type index-type = lb - do (unless (funcall predicate ele (aref seq i)) - (when (> i (1+ ele-idx)) - (rotatef (aref seq ele-idx) (aref seq (1+ ele-idx))) - (rotatef (aref perm ele-idx) (aref perm (1+ ele-idx)))) - (rotatef (aref seq ele-idx) (aref seq i)) - (rotatef (aref perm ele-idx) (aref perm i)) - (incf ele-idx) - #+nil(format t " ~a ~%" seq)) - finally (return ele-idx))))) - (when (> (- ub ele-idx) 2) - (qsort-bounds (1+ ele-idx) ub)) - (when (> (- ele-idx lb) 1) - (qsort-bounds lb ele-idx)))))) - (qsort-bounds 0 len) - (values seq perm)))) - -(quicksort-with-action (idxv 10 9 8 7 6 5 4 3 2 1) #'<) diff --git a/src/standard-tensor.lisp b/src/standard-tensor.lisp index 905fe8e..a780560 100644 --- a/src/standard-tensor.lisp +++ b/src/standard-tensor.lisp @@ -147,7 +147,7 @@ (incf sto-idx (the index-type (* (aref strides i) cidx))) (error 'tensor-index-out-of-bounds :argument i :index cidx :dimension (aref dims i))) finally (return sto-idx)))))) -x + (defun store-indexing-lst (idx hd strides dims) " Syntax @@ -232,7 +232,7 @@ x ;;Error checking is good if we use foreign-pointers as store types. (cond ((< hd 0) (error 'tensor-invalid-head-value :head hd :tensor tensor)) - ((<= ss L-idx) (error 'insufficient-store :store-size ss :max-idx L-idx :tensor tensor))) + ((<= ss L-idx) (error 'tensor-insufficient-store :store-size ss :max-idx L-idx :tensor tensor))) ;; ;;--*TODO: Add checks to see if there is index-collision.*-- ;; This is a hard (NP ?) search problem @@ -258,13 +258,13 @@ x (:method :before ((tensor standard-tensor) idx) (declare (type index-type idx)) (unless (< -1 idx (store-size tensor)) - (error 'store-index-out-of-bounds :index idx :store-size (store-size tensor) :tensor tensor)))) + (error 'tensor-store-index-out-of-bounds :index idx :store-size (store-size tensor) :tensor tensor)))) (defgeneric (setf tensor-store-ref) (value tensor idx) (:method :before (value (tensor standard-tensor) idx) (declare (type index-type idx)) (unless (< -1 idx (store-size tensor)) - (error 'store-index-out-of-bounds :index idx :store-size (store-size tensor) :tensor tensor)))) + (error 'tensor-store-index-out-of-bounds :index idx :store-size (store-size tensor) :tensor tensor)))) (defmacro tensor-store-defs ((tensor-class element-type store-element-type) &key store-allocator coercer reader value-writer reader-writer) (let ((tensym (gensym "tensor"))) diff --git a/src/utilities.lisp b/src/utilities.lisp index 63fef05..fec194e 100644 --- a/src/utilities.lisp +++ b/src/utilities.lisp @@ -90,19 +90,17 @@ (nconc ,var ,@(cdr args))) (nconc ,var ,@args)))) -(defun pop-arg! (sym arglist) +(defun pop-arg! (arglist sym) (check-type sym symbol) - (locally - (declare (optimize (speed 3) (safety 0))) - (labels ((get-sym (sym arglist prev) - (cond - ((null arglist) nil) - ((eq (car arglist) sym) (prog1 + (labels ((get-sym (sym arglist prev) + (cond + ((null arglist) nil) + ((eq (car arglist) sym) (prog1 (cadr arglist) - (if prev - (rplacd prev (cddr arglist))))) - (t (get-sym sym (cdr arglist) arglist))))) - (get-sym sym arglist nil)))) + (if prev + (rplacd prev (cddr arglist))))) + (t (get-sym sym (cdr arglist) arglist))))) + (get-sym sym arglist nil))) (defun slot-values (obj slots) (values-list (mapcar #'(lambda (slt) (slot-value obj slt)) @@ -138,7 +136,7 @@ (defmacro if-let ((var . form) &rest body) (check-type var symbol) - `(let ((,var ,@form)) + `(let ((,var ,@form)) (if ,var ,@body))) commit 3727a088ffe014773472fd37a7d45346917a73a0 Author: Akshay Srinivasan <aks...@gm...> Date: Mon Jul 2 12:56:22 2012 +0530 Added loopy-test into the repo. diff --git a/TODO b/TODO deleted file mode 100644 index 8be2f0a..0000000 --- a/TODO +++ /dev/null @@ -1,8 +0,0 @@ -* Write documentation. Maybe move to TeXinfo (like femlisp). - Fix the formatting for docstrings. -* Write tests -* Get the python-bridge working with burgled-batteries, nothing beats - matplotlib for plotting. -* Add infix to Matlisp -* Support linking to libraries ? Might have to parse function declarations - with cffi-grovel. \ No newline at end of file diff --git a/src/loopy-tests.lisp b/src/loopy-tests.lisp new file mode 100644 index 0000000..fbaafe0 --- /dev/null +++ b/src/loopy-tests.lisp @@ -0,0 +1,83 @@ + +(defun tdcopy (n) + (let* ((t-a (make-real-tensor-dims n n n)) + (st-a (store t-a)) + (t-b (make-real-tensor-dims n n n)) + (st-b (store t-b))) + (with-optimization (:speed 3 :safety 0 :space 0) + (mod-dotimes (idx (idxv n n)) + with (linear-sums + (of (idxv (* n n) n))) + do (dcopy n st-a 1 st-b 1 of of))))) + +(defun tcopy (n) + (let* ((t-a (make-real-tensor-dims n n n)) + (t-b (make-real-tensor-dims n n n))) + (time (real-tensor-copy t-a t-b)))) + +(defun modidx (n dims) + (declare (optimize (speed 3) (safety 0)) + (type index-type n) + (type cons dims)) + (multiple-value-bind (div rem) (let ((div (car dims))) + (declare (type index-type div)) + (floor n div)) + (declare (ignore div)) + (if (null (cdr dims)) t + (modidx rem (cdr dims))))) + +(defun test-mm-lisp (n) + (let ((t-a (make-real-tensor-dims n n)) + (t-b (make-real-tensor-dims n n)) + (t-c (make-real-tensor-dims n n))) + (declare (type real-tensor t-a t-b t-c)) + (let ((st-a (store t-a)) + (st-b (store t-b)) + (st-c (store t-c))) + (declare (type (real-array *) st-a st-b st-c)) + (very-quickly + (mod-dotimes (idx (dimensions t-a)) + with (linear-sums + (of-a (strides t-a)) + (of-b (strides t-b)) + (of-c (strides t-c))) + do (setf (aref st-a of-a) (random 1d0) + (aref st-b of-b) (random 1d0) + (aref st-c of-c) 0d0))) + (time + (very-quickly + (mod-dotimes (idx (idxv n n n)) + with (loop-order :row-major) + with (linear-sums + (of-a (idxv n 1 0)) + (of-b (idxv 0 n 1)) + (of-c (idxv n 0 1))) + do (incf (aref st-c of-c) (* (aref st-a of-a) (aref st-b of-b))))))))) + +(defun test-mm-ddot (n) + (let* ((t-a (make-real-tensor-dims n n)) + (t-b (make-real-tensor-dims n n)) + (t-c (make-real-tensor-dims n n)) + (st-a (store t-a)) + (st-b (store t-b)) + (st-c (store t-c))) + (declare (type real-tensor t-a t-b t-c) + (type (real-array *) st-a st-b st-c)) + (mod-dotimes (idx (dimensions t-a)) + with (linear-sums + (of-a (strides t-a)) + (of-b (strides t-b)) + (of-c (strides t-c))) + do (setf (aref st-a of-a) (random 1d0) + (aref st-b of-b) (random 1d0) + (aref st-c of-c) 0d0)) + (time + (very-quickly + (mod-dotimes (idx (idxv n n)) + with (loop-order :row-major) + with (linear-sums + (of-a (idxv n 0)) + (of-b (idxv 0 1)) + (of-c (idxv n 1))) + do (setf (aref st-c of-c) + (ddot n st-a 1 st-b n of-a of-b))))))) ----------------------------------------------------------------------- Summary of changes: TODO | 8 - matlisp.asd | 2 + src/conditions.lisp | 134 ++++++++++++-------- src/loopy-tests.lisp | 83 ++++++++++++ src/permutation.lisp | 317 ++++++++++++++++++++++++++++++++++++++++++++++ src/permutations.lisp | 230 --------------------------------- src/standard-tensor.lisp | 8 +- src/utilities.lisp | 22 ++-- 8 files changed, 497 insertions(+), 307 deletions(-) delete mode 100644 TODO create mode 100644 src/loopy-tests.lisp create mode 100644 src/permutation.lisp delete mode 100644 src/permutations.lisp hooks/post-receive -- matlisp |