;; common-lisp main functions
;;

;;;;;;;;;;;;;;;;
;; required
;(load "/Users/fred/PWGL-User/User-library/fv-morphologie/package.lisp")
;(load "/Users/fred/PWGL-User/User-library/fv-morphologie/fv-morphologie.lisp")
;(load "/Users/fred/PWGL-User/User-library/fv-morphologie/fv-morphologie-encodage.lisp")
;(load "/Users/fred/PWGL-User/User-library/fv-morphologie/fv-morphologie-io.lisp")
;(load "/Users/fred/PWGL-User/User-library/fv-morphologie/fv-morphologie-graphs.lisp")

(in-package :fv-morphologie)

;; MENU
;;;;;;;;;;;;;;;;
;;; 1. DIFFERENTIATION
;;; 1.1 SEGMENTATION
;;; 1.1.1 INTENSITIES

(defmethod int-sign ((seq t) &key (pos nil) (thres 0)) ; old dsign
  "Sign of variation of intensities : -1 for decreasing, 1 for increasing, 0 for constant.
Optional argument <pos>, if T returns each sign of variations consed to its position in sequence <seq>,
or only signs of variations if NIL.
Optional argument <thres> is the threshold for detecting only variations higher than <thres>,
and variations smaller than <thres> are considered as constant (zéro). Value of <thres> from 0.0 to 1.0, relative to the overall range of intensity values."
  (fv-morphologie::dsign seq thres pos))

(defmethod int-primitives ((seq t)  &optional (out :prim) (thres nil))
  "Returns the sequence of primitives describing the sequence <seq>.
Optional menu <out> defines the output type:
 :prim for primitives only
 :pos for primitives and their positions in <seq>
 :amp for primitives, their positions and amplitudes.
Last optional argument <thres> fixes the minimum treshold for detecting a primitive according to its amplitude."
  (fv-morphologie::primitives seq out thres))

(defmethod def-primitives ((arg1 t) &rest args)
  "Defines the symbols to represent each primitive.
If using just one argument, the value ':num' calls the symbols -1, 0 and 1, when ':sym' calls the strings 'min' 'flex' 'max'.
If using several arguments, each define explicitly each primitive by consing a primitive description in numerical representation - for instance: (1 -1) for acendind-descending - followed by any arbitrary symbol to represent it." 
  (eval `(fv-morphologie::prim-def ,arg1 ,.args)))


;;; 1.1.2 MARKS

(defmethod mark-list ((seq t) (mark t) &key (mark-t #'equalp) (seg-t #'equalp))
  "Returns the list of all segments and their position in <seq> beginning with some marks defined with argument <mark>.
If no argument mark (nil), considers all different symbols in <seq>.
Option :mark-t defines the test function for searching the marks (equalp by default).
Option :group-t defines the test function for comparing the different segments."
  (when (and (symbolp mark-t) (not (boundp mark-t))) (setf mark-t (eval `(function ,mark-t))))
  (when (and (symbolp seg-t) (not (boundp seg-t))) (setf group-t (eval `(function ,seg-t))))
  (fv-morphologie::mark-pos seq mark mark-t seg-t))

(defmethod mark-structure  ((seq t) (out t) &key (diss 0) (rem-loc-dup t) (test #'equalp))
  "Returns possible structures of input <seq> based on marks retrieved from <seq>.
The output is sorted by structures's length.
Use output menu <out> to define result form:
:struct lists all possible structures according to different marks of <seq>
:pos each structure is consed to the list of positions for each segment followed by the list of the segments themselves
:raw each structure is consed to the list of each segment with its positions in <seq>.
Option :diss defines the dissemblance threshold to consider different segment as the same.
Option :test defines the test function to consider the marks."
  (when not out (setf out :struct))
  (fv-morphologie::mark-strct seq out diss rem-loc-dup test))

;;; 1.1.3 MOTIFS

(defmethod motif-subseq ((motif t) (seq t) &optional (test #'equalp))
  "Tests if a motif is a subsequence of a sequence.
The test is based on the editing distance where each elements are compared to others according to the optional argument <test>."
  (fv-morphologie::subseq-p motif seq test))

(defmethod motif-list ((seq t) (out t)
		       &key (diss 0) (l-var 0) (n nil) (change 1) (insert 1) (delete 1) (uncom 0) (test #'equalp))
  "Returns the list of all motifs found into <seq> where a motif is any segment repeted at least one time according to editing distance.
Output can be sorted according to the length of segment (:length) or to their frequency (:freq).
Argument :diss is a threshold (from 0 to 1.0) of dissimilarity according to the normalized editing distance under which two different segments are considered to be the same ;
argument :l-var is the threshold for variation in length of the segments to be compared ;
argument :n is the maxinum length of segments to be compared ;
arguments :change :ins/sup :uncom and :test for tuning the editing distance (see dist-edit)."
  (when (not out) (set out :length))
  (fv-morphologie::find-self seq out diss l-var n change insert delete uncom test))

(defmethod motif-find ((motif t) (seq t) &key (diss 0) (l-var 0) (change 1) (insert 1) (delete 1) (uncom 0) (test #'equalp))
  "Returns all the positions of the segment <motif> into sequence <seq>.
Argument :diss is a threshold (from 0 to 1.0) of dissimilarity according to the normalized editing distance under which two different segments are considered to be the same ;
argument :l-var is the threshold for variation in length of the motifs to be compared ;
arguments :change :ins/sup :uncom and :test for tuning the editing distance (see dist-edit)."
  (fv-morphologie::find-pos motif seq diss l-var change insert delete uncom test))

(defmethod  motif-structure ((seq t))
  "To be set"
  (fv-morphologie::rep-strct seq))

;;; 1.2 CLASSIFICATION

(defmethod class-num ((data t) (classes integer) (mode symbol) &key (iter nil) (dist nil))
  "Classify a set (list) of points <data> into different <classes> into s space with n dimensions (n integer > 0),
where each point is represented as a list of values into each dimension.
Argument :mode defines the algorithm used for partioning the points.
:centroids for centroids algorithm (in french : nuees dynamiques.
Keyword argument :iter to set the maximum iterations to run for partitioning ;
:dist to set the distance or metric to be used (by default: euclidian distance)."
  (case mode
    (nil (fv-morphologie::n-class data classes iter dist))
    (:centroids (fv-morphologie::n-class data classes iter dist))
    (:1d-centroids (fv-morphologie::1d-class data classes (if dist dist #'identity))) 
     (t nil)))

(defmethod class-sym ((data t) (classes integer) (mode symbol) &key (uncom .5) (ins 1) (del 1) (change 1) (excluded nil) (mst nil))
  "Classify a set of segments or sequences into different classes according to their editing distance to each other and
by partitioning the resulting spanning tree (see class-graph).
The output is a list of numbers (from zero) as instances of the different classes retrieved.
Keyword arguments :uncom :ins/del :change for tuning editing distance (see dist-edit).
The argument :excluded is a list of elements of data excluded from classification ;
in the output, the numbering of the different instances begins by numbering these elements first (from zero), 
in the order defined with the argument :excluded."
  (if (not excluded)
      (cond ((or (eq mode :edit-nn) (not mode))
             (fv-morphologie::s-class data classes nil change ins del uncom mst))
            ((eq mode :edit-norm)
             (fv-morphologie::s-class data classes t change ins del uncom mst))
            (t nil))
    (cond ((eq mode :edit-nn)
           (fv-morphologie::s-class-with-fixed data classes excluded nil nil nil change ins del uncom mst))
          ((eq mode :edit-norm)
           (fv-morphologie::s-class-with-fixed data classes excluded nil nil t change ins del uncom mst))
          (t nil))))

;;; 1.3 CONCATENATION
;(menu-separator :in differentiation)
;(defmethod concaten ((list nil))
;  :non-generic t
;  :class morphologie-box
;  (fv-morphologie::concaten list))

;(defmethod adj-group ((seq nil) (test #'eq) &optional (key nil))
;  :non-generic t
;  :class morphologie-box
;  (fv-morphologie::adj-group seq test key))

;;;;;;;;;;;;;;;;
;;; 2. EVALUATION
;;; 2.1 DISTANCE

(defmethod dist-euclidian ((a t) (b t))
  "Euclidian distance between points a and b.
Point coordinates are represented by a list of values in any euclidian space with n dimensions (n integer > 0).
The dimensionality of the euclidian space is defined by the list representing <a> and <b>.
 If a is a list of coordinates (lists) and b null,
output is the list of distances for all points to all others ;
 if a or b is a number, consider b or a as list of numbers (1 dim).
If a and b are lists with not same size (i.e points with not same dimensions),
 returns NIL (no distance)."
  (fv-morphologie::dist-euclid a b))

(defmethod dist-citybloc ((a t) (b t))
 "City-bloc distance between <x> and <y> which represent 'points' into kind of euclidian space.
If <y> is null, <x> may represent a list of points, then the output is the list of city-bloc distances for all points to all others."
  (fv-morphologie::city-bloc a b))

(defmethod dist-hamming ((a t) (b t) &optional (norm t) (test #'eq))
  "Hamming distance between list a and list b."
  (fv-morphologie::hamming-dist a b norm test))

;;; DISSEMBLANCE (dissimilarity)

(defmethod dist-edit ((seq1 t) (seq2 t)
		      &key (sub 1) (ins 1) (del 1) (uncom 0) (norm NIL) (test #'equalp))
  (fv-morphologie::edit-dist seq1 seq2 sub ins del uncom norm test))

(defmethod dist-multi-edit ((seq1 t) (seq2 t) (wgth number)
			    &key (sub 1) (ins 1) (del 1) (uncom 0) (test #'equalp))
  (fv-morphologie::multi-edit-dist seq1 seq2 wgth sub ins del uncom test))

;(defmethod resembl-p  ((a t) (b t) (thresh .1)  &optional (inex 0) (test #'equalp))
;  :non-generic t
;  :class morphologie-box
;  (fv-morphologie::resembl-p a b thresh inex test))

(defmethod dist-structure  ((a t) (b t) &key (w-occ 1.) (w-rep 1.) (test #'equalp))
  (fv-morphologie::struct-dist a b w-occ w-rep test))

(defmethod dist-graph ((v1 t) (v2 t) (graph t))
  (fv-morphologie::tree-dist v1 v2 graph))


;;; 2.2 DESCRIPTION - STATS - INFORMATION

(defmethod histogram ((data t) &key (test #'=) (thes nil))
  (fv-morphologie::histogramme data :test test :thes thes))

(defmethod entropy ((data t) &optional (mode nil) (samples nil))
  (cond ((not mode)
	 (message "Entropy: using 'shannon-2 mode (default).")
	 (shannon-entropy data 2 samples))
	((eq mode 'shannon-2)
	 (shannon-entropy data 2 samples))
	((eq mode 'shannon-e)
	 (shannon-entropy data (exp 1) samples))
	((eq mode 'shannon-n)
	 (shannon-entropy data nil samples))
	((eq mode 'cond-sh)
	 (entropie-conditionnelle data nil samples))
    (t (message "Entropy: unknown mode. Avalaible modes are: 'shannon-2, 'shannon-n, shannon-e."))))

(defmethod elt-info ((data t) (elt t) &optional (test #'equalp))
  (fv-morphologie::self-info data elt test))

;(defmethod redundancy ((data t))
;  :non-generic t
;  :class morphologie-box
;  (fv-morphologie::redondance data))

(defmethod  inner-dynamic ((seq t) &optional (test #'equalp))
  (fv-morphologie::mark-dynamic seq test))

;;;;;;;;;;;;;;;;
;;; 3. DELINEATION
;;; 3.1 BUILDING SOME GRAPHS

(defmethod graph-span ((mat-dist t))
  (fv-morphologie::minimum-spanning-tree mat-dist))

(defmethod graph-part ((graph t) &optional (mode :distance))
  "Partition a graph according according to edges which have maximum length."
  (fv-morphologie::part-graph graph mode))

;;; 3.2 MEASURING GRAPHS

(defmethod graph-path ((from t) (to t) (tree t))
  (fv-morphologie::tree-path from to tree))

(defmethod graph-len ((graph t))
  (fv-morphologie::tree-minlen graph))

(defmethod graph-deg ((node t) (graph t))
  (fv-morphologie::tree-deg node graph))

(defmethod graph-nodes ((graph t))
  (fv-morphologie::tree-nodes graph))

;;; 3.3 DRAWING

(defmethod graph>dot  ((graph t) (distorsion number) (scale t) (out t) &key (shape "ellipse") (legend t) (neato nil))
  "Converts a graph (list of edges) into an undirected graph into dot langage to be processed using neato program.
Arguments are:
graph : the graph, as a structured list.
distorsion : amount of distortion allowed for distances fir drawing the graph (from 0.0 for minimum distorsion to 1.0 maximum distorsion)
scale : scaling factor for the mininum distance
shape : string or list of strings to define node's shape, using 'neato' definitions
out :
if NIL or T, print out in listener;
if a string, it defines the pathname of the output. Type of file define output.
"
  (fv-morphologie::graph>dot graph distorsion scale shape out legend (if (or (stringp neato) (pathnamep neato)) neato nil)))


;;;;;;;;;;;;;;;;
;;; 4. ENCODING
;;; 4.1 TRANSCODING

(defmethod split ((seq t) (marks t))
  (if (and seq marks)
      (cond ((listp seq)
	     (split-list-using-marks seq marks))
	    ((stringp seq)
	     (split-string seq marks))
	    (t seq))
      seq))

(defmethod concaten ((seq t))
  (fv-morphologie::concat seq))

(defmethod transcode ((seq t) (table t) &optional (test #'eq))
  (fv-morphologie::transcode seq table test))

(defmethod num>base ((num number) (base t))
  (fv-morphologie::num-base num base))

(defmethod num>alpha ((num number))
  (fv-morphologie::num>alpha num))

(defmethod alpha>num ((alpha t) &optional (mode nil))
  (fv-morphologie::alpha>num alpha))

(defmethod list>sym ((list t))
  (fv-morphologie::concaten list))

(defmethod graph>matrix ((list t))
  (fv-morphologie::graph2matrix list))

;;; 4.2 TOOLS

(defmethod filt-median ((seq t) (window number))
  "median filter"
  (fv-morphologie::median-filter seq window))

(defmethod filt-exponential ((seq t) (alpha number) &optional (gamma nil))
  "Low-pass filter"
  (if (not gamma)
      (fv-morphologie::exponential-smoothing seq alpha)
    (fv-morphologie::double-exponential-smoothing seq alpha gamma)))

(defmethod filt-local-rep ((seq t) &optional (mode nil) (test #'equalp))
  "Delete identical values or symbols."
  (cond ((eq mode :delete)
         (fv-morphologie::rem-local-rep seq test))
        ((eq mode :linear)
         (if (not (member 'nil (mapcar #'numberp seq)))
             (fv-morphologie::nocons= seq test)
           (fv-morphologie::filt-local-rep seq :delete test)))
        (t (fv-morphologie::filt-local-rep seq :delete test))))

(defmethod filt-noise ((seq t) &optional (mode :nozero) (val 0.1))
  "Add noise into seq seq"
  (fv-morphologie::fnoise seq mode val))

;;;;;;;;;;;;;;;;
;;; 5. IMPORT-EXPORT
;;; 5.1 reading files

(defmethod read-text ((file t)  (mode t) &key (sep nil) (rem-test nil))
  (read-txt-file file :mode mode :marks sep :rem-test rem-test))

; (defmethod read-midi ((file))
; (defmethod read-sdif ((file))

;;; 5.2 writing files

(defmethod write-list ((list list) (file t) &optional (mode :supersede))
  (list-write list file mode))
