|
From: Akshay S. <ak...@us...> - 2012-04-14 12:06:15
|
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 created
at 365629a9b8ca20f729635ec74047904caca9c8d9 (commit)
- Log -----------------------------------------------------------------
commit 365629a9b8ca20f729635ec74047904caca9c8d9
Author: Akshay Srinivasan <aks...@gm...>
Date: Sat Apr 14 17:29:29 2012 +0530
Real-tensor class sort of works.
diff --git a/src/real-tensor.lisp b/src/real-tensor.lisp
new file mode 100644
index 0000000..e5bebaf
--- /dev/null
+++ b/src/real-tensor.lisp
@@ -0,0 +1,53 @@
+(in-package :tensor)
+
+(eval-when (load eval compile)
+ (deftype real-type ()
+ "The type of the elements stored in a REAL-MATRIX"
+ 'double-float)
+
+ (deftype real-array (size)
+ "The type of the storage structure for a REAL-MATRIX"
+ `(simple-array real-type (,size)))
+ )
+;;
+(declaim (inline allocate-real-store))
+(defun allocate-real-store (size &optional (initial-element 0d0))
+ (make-array size :element-type 'real-type
+ :initial-element (coerce initial-element 'real-type)))
+
+(declaim (inline coerce-real))
+(defun coerce-real (x)
+ (coerce x 'real-type))
+
+;;
+(defclass real-tensor (standard-tensor)
+ ((store
+ :initform nil
+ :type (real-array *)))
+ (:documentation "Tensor class with real elements."))
+
+(defclass sub-real-tensor (real-tensor)
+ ((parent-tensor
+ :initarg :parent-tensor
+ :accessor parent-tensor))
+ (:documentation "Sub-tensor class with real elements."))
+
+;;
+(defmethod initialize-instance ((tensor real-tensor) &rest initargs)
+ (setf (store-size tensor) (length (get-arg :store initargs)))
+ (call-next-method))
+;;
+
+(defmethod tensor-store-ref ((tensor real-tensor) (idx fixnum))
+ (aref (store tensor) idx))
+
+(defmethod (setf tensor-store-ref) ((value number) (tensor real-tensor) (idx fixnum))
+ (setf (aref (store tensor) idx) (coerce-real value)))
+
+;;
+
+(defun make-real-tensor (&rest subs)
+ (let* ((dims (apply #'make-index-store subs))
+ (ss (reduce #'* dims))
+ (store (allocate-real-store ss)))
+ (make-instance 'real-tensor :store store :dimensions dims)))
\ No newline at end of file
diff --git a/src/standard-tensor.lisp b/src/standard-tensor.lisp
new file mode 100644
index 0000000..959988c
--- /dev/null
+++ b/src/standard-tensor.lisp
@@ -0,0 +1,348 @@
+(defpackage :tensor
+ (:use :cl :utilities))
+
+(in-package :tensor)
+
+;;
+(declaim (inline allocate-integer4-store))
+
+(eval-when (load eval compile)
+ (deftype int32-type ()
+ '(signed-byte 32))
+ (deftype int32-array (size)
+ `(simple-array int32-type (,size)))
+
+ ;;
+ (deftype index-type ()
+ 'fixnum)
+ (deftype index-array (size)
+ `(simple-array index-type (,size)))
+ )
+
+(defun allocate-int32-store (size &optional (initial-element 0))
+ "(ALLOCATE-INTEGER-STORE SIZE [INITIAL-ELEMENT]). Allocates
+integer storage. Default INITIAL-ELEMENT = 0."
+ (make-array size
+ :element-type 'int32-type
+ :initial-element initial-element))
+
+(defun allocate-index-store (size &optional (initial-element 0))
+ (make-array size :element-type 'index-type
+ :initial-element initial-element))
+
+(defun make-index-store (&rest contents)
+ (let ((size (length contents)))
+ (make-array size :element-type 'index-type
+ :initial-contents contents)))
+
+;;
+(defun store-indexing-internal (idx strides &optional (hd (the index-type 0)))
+ "No explicit error checking, meant to be used internally.
+ Returns
+
+ length(strides)
+ __
+ hd + \ stride * idx
+ /_ i i
+ i = 0
+
+ "
+ (declare (type index-type hd)
+ (type (index-array *) idx strides))
+ (let ((rank (length strides)))
+ (declare (type index-type rank))
+ (the index-type (+ hd
+ (do ((i 0 (+ i 1))
+ (sto-idx (the index-type 0) (the index-type
+ (+ sto-idx
+ (the index-type
+ (* (the index-type
+ (aref idx i))
+ (the index-type
+ (aref strides i))))))))
+ ((= i rank) sto-idx))))))
+
+
+(defun store-indexing-vec (idx strides dims &optional (hd (the index-type 0)))
+ "
+ Returns
+
+ length(strides)
+ __
+ hd + \ stride * idx
+ /_ i i
+ i = 0
+
+ "
+ (declare (type index-type hd)
+ (type (index-array *) idx strides))
+ (let ((rank (length strides)))
+ (declare (type index-type rank))
+ (unless (= rank (length idx))
+ (error "Wrong number of subscripts for a array of rank ~A" rank))
+ (the index-type (+ hd
+ (do ((i 0 (+ i 1))
+ (sto-idx (the index-type 0) (the index-type
+ (+ sto-idx
+ (the index-type
+ (* (the index-type
+ (aref strides i))
+ ;;
+ (the index-type
+ (let ((cidx (aref idx i)))
+ (unless (< -1 cidx (aref dims i))
+ (error "Requested index ~A for argument ~A is out of bounds.
+Tensor only has dimension ~A for the ~A argument." cidx i (aref dims i) i))
+ cidx))))))))
+ ((= i rank) sto-idx))))))
+
+
+(defun store-indexing-lst (idx strides dims &optional (hd (the index-type 0)))
+ "
+ Returns
+
+ length(strides)
+ __
+ hd + \ stride * idx
+ /_ i i
+ i = 0
+
+ "
+ (declare (type index-type hd)
+ (type (index-array *) strides)
+ (type cons idx))
+ (let ((rank (length strides)))
+ (declare (type index-type rank))
+ (the index-type (+ hd
+ (let ((idx-sum (the index-type 0)))
+ (do ((i 0 (+ i 1))
+ (ilst idx (cdr ilst)))
+ ((= i rank) (if (null ilst)
+ idx-sum
+ (error "Too many subscripts for a tensor of rank ~A" rank)))
+ (let ((cidx (car ilst)))
+ (when (null cidx)
+ (error "Too few subscripts for a tensor of rank ~A" rank))
+ (unless (< -1 cidx (aref dims i))
+ (error "Requested index ~A for argument ~A is out of bounds.
+Tensor only has dimension ~A for the ~A argument." cidx i (aref dims i) i))
+ ;;
+ (setf idx-sum (the index-type (+ idx-sum
+ (the index-type
+ (*
+ (the index-type cidx)
+ (the index-type (aref strides i))))))))))))))
+
+;;
+(defclass standard-tensor ()
+ ((rank
+ :accessor rank
+ :type index-type
+ :documentation "Rank of the tensor: number of arguments for the tensor")
+ (dimensions
+ :accessor dimensions
+ :initarg :dimensions
+ :type (index-array *)
+ :documentation "Dimensions of the vector spaces in which the tensor's arguments reside.")
+ (number-of-elements
+ :accessor number-of-elements
+ :type index-type
+ :documentation "Total number of elements in the tensor.")
+ ;;
+ (head
+ :initarg :head
+ :initform 0
+ :accessor head
+ :type index-type
+ :documentation "Head for the store's accessor.")
+ (strides
+ :initarg :strides
+ :accessor strides
+ :type (index-array *)
+ :documentation "Strides for accesing elements of the tensor.")
+ (store-size
+ :accessor store-size
+ :type index-type
+ :documentation "Size of the store.")
+ (store
+ :initarg :store
+ :accessor store
+ :documentation "The actual storage for the tensor."))
+ (:documentation "Basic tensor class."))
+
+;;
+(defun store-indexing (idx tensor)
+ (declare (type standard-tensor tensor)
+ (type (or cons (index-array *)) idx))
+ (typecase idx
+ (cons (store-indexing-lst idx (strides tensor) (dimensions tensor) (head tensor)))
+ (vector (store-indexing-lst idx (strides tensor) (dimensions tensor) (head tensor)))))
+
+;;
+(defmethod initialize-instance :after ((tensor standard-tensor) &rest initargs)
+ (declare (ignore initargs))
+ (mlet*
+ (((dims hd ss) (slot-values tensor '(dimensions head store-size))
+ :type ((index-array *) index-type index-type))
+ (rank (length dims) :type index-type))
+ ;;Let the object be consistent.
+ (setf (rank tensor) rank)
+ ;;Row-ordered by default.
+ (unless (and (slot-boundp tensor 'strides)
+ (= (length (strides tensor)) rank))
+ (mlet* ((stds (allocate-index-store rank)
+ :type (index-array *)))
+ (setf (strides tensor) stds)
+ (do ((i (1- rank) (1- i))
+ (st 1 (* st (aref dims i))))
+ ((< i 0))
+ (setf (aref stds i) st))))
+ ;;
+ (mlet* ((stds (strides tensor) :type (index-array *))
+ (L-idx (store-indexing-vec (map `(index-array *) #'1- dims) stds dims hd) :type index-type))
+ ;;Error checking is good if we use foreign-pointers as store types.
+ (cond
+ ((< hd 0) (error "Head of the store must be >= 0. Initialized with ~A." hd))
+ ((<= ss L-idx) (error "Store is not large enough to hold the matrix.
+Initialized with ~A, but the largest possible index is ~A." ss L-idx)))
+ ;;
+ (dotimes (i rank)
+ (let ((ns (aref dims i))
+ (st (aref stds i)))
+ (cond
+ ((<= ns 0) (error "Dimension ~A must be > 0.
+Initialized with ~A." i ns))
+ ((< st 0) (error "Stride of dimension ~A must be >= 0.
+Initialized with ~A." i st))))))
+ ;;
+ (setf (number-of-elements tensor) (reduce #'* dims))))
+
+;;
+(defgeneric tensor-store-ref (tensor store-idx)
+ (:documentation "
+ Syntax
+ ======
+ (tensor-ref-1d store store-idx)
+
+ Purpose
+ =======
+ Return the element store-idx of the tensor store."))
+
+(defmethod tensor-store-ref :before ((tensor standard-tensor) (idx fixnum))
+ (unless (< -1 idx (store-size tensor))
+ (error "Requested index ~A is out of bounds.
+Tensor-store only has ~A elements." idx (store-size tensor))))
+
+;;
+(defgeneric (setf tensor-store-ref) (value matrix idx))
+
+(defmethod (setf tensor-store-ref) :before ((value t) (tensor standard-tensor) (idx fixnum))
+ (unless (< -1 idx (store-size tensor))
+ (error "Requested index ~A is out of bounds.
+Tensor-store only has ~A elements." idx (store-size tensor))))
+
+;;
+(defgeneric tensor-ref (tensor &rest subscripts)
+ (:documentation "
+ Syntax
+ ======
+ (tensor-ref store &rest subscripts)
+
+ Purpose
+ =======
+ Return the element:
+
+ (rank - 1)
+ __
+ hd + \ stride * sub
+ /_ i i
+ i = 0
+
+ of the store "))
+
+(defmethod tensor-ref ((tensor standard-tensor) &rest subscripts)
+ (let ((sto-idx (store-indexing subscripts tensor)))
+ (tensor-store-ref tensor sto-idx)))
+
+;;
+(defgeneric (setf tensor-ref) (value tensor &rest subscripts))
+
+(defmethod (setf tensor-ref) ((value t) (tensor standard-tensor) &rest subscripts)
+ (let ((sto-idx (store-indexing subscripts tensor)))
+ (setf (tensor-store-ref tensor sto-idx) value)))
+
+;;
+;; TODO: Pretty-ify by borrowing from src/print.lisp
+(defmethod print-object ((tensor standard-tensor) stream)
+ (let ((rank (rank tensor))
+ (dims (dimensions tensor)))
+ (labels ((rec-print (tensor idx subs)
+ (if (> idx 1)
+ (dotimes (i (aref dims idx))
+ (rec-print tensor (1- idx) (cons i subs)))
+ (progn
+ (format stream "~A~%" (append (list '\: '\:) subs))
+ (dotimes (i (aref dims 0))
+ (dotimes (j (aref dims 1))
+ (format stream "~A~,4T" (apply #'tensor-ref (cons tensor (append (list i j) subs)))))
+ (format stream "~%~%"))))))
+ (format stream "<TENSOR(~A) ~A>~%" rank dims)
+ (if (= rank 1)
+ (progn
+ (dotimes (i (aref dims 0))
+ (format stream "~A~,4T" (tensor-ref tensor i)))
+ (format stream "~%"))
+ (rec-print tensor (- rank 1) nil)))))
+;;
+(defun tensor-type-p (tensor &rest subscripts)
+ "
+ Syntax
+ ======
+ (tensor-ref tensor &rest subscripts)
+
+ Purpose
+ =======
+ Check if the given tensor is of particular sizes in particular
+ arguments.
+
+ Checking if the tensor is a vector would then be:
+ (tensor-type-p ten t)
+
+ Checking if it is a matrix with 2 columns would be:
+ (tensor-type-p ten t 2)
+ "
+ (declare (type standard-tensor tensor))
+ (mlet* (((rank dims) (slot-values tensor '(rank dimensions))
+ :type (index-type (index-array *))))
+ (let ((syms->val (make-hash-table)))
+ (labels ((parse-sub (lst i)
+ (let ((val (car lst)))
+ (cond
+ ((= i rank) t)
+ ((null val) nil)
+ ((eq val t) (parse-sub (cdr lst) (1+ i)))
+ (t (progn
+ (when (symbolp val)
+ (multiple-value-bind (hash-val existp) (gethash val syms->val)
+ (if existp
+ (setq val hash-val)
+ (setf (gethash val syms->val) (aref dims i)
+ val (aref dims i)))))
+ (if (= val (aref dims i))
+ (parse-sub (cdr lst) (1+ i))
+ nil)))))))
+ (parse-sub subscripts 0)))))
+
+(defun vector-p (tensor)
+ (declare (type standard-tensor tensor))
+ (tensor-type-p tensor t))
+
+(defun matrix-p (tensor)
+ (declare (type standard-tensor tensor))
+ (tensor-type-p tensor t t))
+
+(defun square-p (tensor)
+ (let* ((rank (rank tensor))
+ (sym (gensym))
+ (lst (make-list rank :initial-element sym)))
+ (apply #'tensor-type-p (cons tensor lst))))
\ No newline at end of file
-----------------------------------------------------------------------
hooks/post-receive
--
matlisp
|