;;; -*-  Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;     The data in this file contains enhancments.                    ;;;;;
;;;                                                                    ;;;;;
;;;  Copyright (c) 1984,1987 by William Schelter,University of Texas   ;;;;;
;;;     All rights reserved                                            ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;     (c) Copyright 1981 Massachusetts Institute of Technology         ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package :maxima)

(macsyma-module array)

;;; Macsyma User array utilities originally due to CFFK.

;;; Note that on the lisp level we regard as an array either
;;;   (1) a symbol whose ARRAY property is a common lisp array
;;;       [i.e., (symbol-array 'symbol)
;;;               == (get 'symbol 'array) => some array] or
;;;   (2) a common lisp array.
;;; On the maxima level a declared array not of type HASH or FUNCTIONAL 
;;; is either
;;;   (1m) a symbol whose ARRAY mproperty is of type (1)
;;;        [i.e., (symbol-array (mget 'symbol 'array)) => some array] or
;;;   (2m) it is of type (2) (and then called a `fast' array).
;;; Such an array is of type (1m) iff it was created with ARRAY 
;;; with USE_FAST_ARRAYS being set to FALSE.
;;;
;;; Curiously enough, ARRAY(...,TYPE,...) (which currently can only be
;;; used for USE_FAST_ARRAYS:FALSE) results in an array which is
;;; simultaneously of type (1) and (1m).

(defmfun $listarray (ary)
  (cons '(mlist)
	(cond ((mget ary 'hashar)
	       (mapcar #'(lambda (subs) ($arrayapply ary subs))
		       (cdddr (meval (list '($arrayinfo) ary)))))
	      ((mget ary 'array) (listarray (mget ary 'array)))
              ((arrayp ary)
               (if (eql (array-rank ary) 1)
                   (coerce ary 'list)
                   (coerce (make-array (apply '* (array-dimensions ary))
                                       :displaced-to ary
                                       :element-type (array-element-type ary))
                           'list)))
	      ((hash-table-p ary)
	       (let (vals (tab ary))
                 (maphash #'(lambda (x &rest l) l 
                              (unless (eq x 'dim1) (push (gethash x tab) vals)))
                            ary)
	         (reverse vals)))
	      ((eq (marray-type ary) '$functional)
	       (cdr ($listarray (mgenarray-content ary))))
	      (t 
	       (merror (intl:gettext "listarray: argument must be an array; found: ~M")
	               ary)))))

(defmfun $fillarray (ary1 ary2)
  (let ((ary
	 (or (mget ary1 'array)
	     (and (arrayp ary1) ary1)
	     (merror (intl:gettext "fillarray: first argument must be a declared array; found: ~M") ary1))))
    (fillarray ary
	       (cond (($listp ary2) (cdr ary2))
		     ((get (mget ary2 'array) 'array))
		     ((arrayp ary2) ary2)
		     (t
		      (merror (intl:gettext "fillarray: second argument must be an array or list; found: ~M") ary2))))
    ary1))

(defun getvalue (sym)
  (and (symbolp sym) (boundp sym) (symbol-value sym)))

(defmspec $rearray (l)
  (setq l (cdr l))
  (let ((ar (car l))
	(dims (mapcar #'meval (cdr l))))
    (cond ($use_fast_arrays
	   (setf (symbol-value ar) (rearray-aux ar (getvalue ar) dims)))
	  (t
	   (rearray-aux ar (getvalue ar) dims)))))

(defun rearray-aux (ar val dims &aux marray-sym)
  (cond ((arrayp val)
	 (apply 'lispm-rearray val dims))
	((arrayp (get ar 'array))
	 (setf (get ar 'array) (apply 'lispm-rearray (get ar 'array) dims)))
	((setq marray-sym (mget ar 'array))
	 (rearray-aux marray-sym nil dims)
	 ar)
	(t (merror (intl:gettext "rearray: argument is not an array: ~A") ar))))

(defun lispm-rearray (ar &rest dims)
  (cond ((eql (array-rank ar) (length dims))
	 (adjust-array ar (mapcar #'1+ (copy-list dims)) :element-type (array-element-type ar)  ))
	(t (merror (intl:gettext "rearray: arrays must have the same number of subscripts.")))))
