55c796d79111

Add `window` and a few other things that have been sitting around
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Wed, 10 Nov 2021 21:13:00 -0500
parents eb9bf5de0279
children 1b8a1cc764c4
branches/tags (none)
files DOCUMENTATION.markdown make-docs.lisp src/debugging.lisp src/gnuplot.lisp src/iterate.lisp src/package.lisp src/shell.lisp

Changes

--- a/DOCUMENTATION.markdown	Mon Jul 12 22:03:01 2021 -0400
+++ b/DOCUMENTATION.markdown	Wed Nov 10 21:13:00 2021 -0500
@@ -179,6 +179,33 @@
 
   
 
+## Package `LOSH.BASE`
+
+A few utilities re-exported from Alexandria, plus some other basic stuff.
+
+### `MKSTR` (function)
+
+    (MKSTR &REST ARGS)
+
+### `SYMB` (function)
+
+    (SYMB &REST ARGS)
+
+### `TIMING` (macro)
+
+    (TIMING (&KEY (TIME :RUN) (RESULT-TYPE 'INTEGER))
+      &BODY
+      BODY)
+
+Execute `body`, discard its result, and return the time taken.
+
+  `time` must be one of `:run` or `:real`.
+
+  `result-type` must be `integer` (which will return internal time units) or
+  `rational`/`single-float`/`double-float` (which will return seconds).
+
+  
+
 ## Package `LOSH.BITS`
 
 Utilities for low-level bit stuff.
@@ -1181,7 +1208,7 @@
 
 ### `PLOT` (function)
 
-    (PLOT DATA &KEY (STYLE :LINESPOINTS) (FILE plot.pdf))
+    (PLOT DATA &KEY (STYLE :LINESPOINTS) (FILE plot.pdf) (LOGSCALE NIL))
 
 Plot `data` with gnuplot.
 
@@ -2596,8 +2623,9 @@
   completes.  If false, it will return immediately and allow the program to run
   asynchronously.
 
-  `input` must be a character input stream, a string, or `nil`.  If non-`nil`
-  its contents will be sent to the program as its standard input.
+  `input` must be a character input stream, a string, a list of strings, or
+  `nil`.  If non-`nil` its contents will be sent to the program as its standard
+  input.  A list of strings will be sent separated by newlines.
 
   `result-type` must be one of:
 
--- a/make-docs.lisp	Mon Jul 12 22:03:01 2021 -0400
+++ b/make-docs.lisp	Wed Nov 10 21:13:00 2021 -0500
@@ -4,6 +4,7 @@
   (list "LOSH"
 
         "LOSH.ARRAYS"
+        "LOSH.BASE"
         "LOSH.BITS"
         "LOSH.CHILI-DOGS"
         "LOSH.CLOS"
--- a/src/debugging.lisp	Mon Jul 12 22:03:01 2021 -0400
+++ b/src/debugging.lisp	Wed Nov 10 21:13:00 2021 -0500
@@ -210,6 +210,31 @@
        (stop-profiling))))
 
 
+(defmacro timing ((&key (time :run) (result-type 'integer)) &body body)
+  "Execute `body`, discard its result, and return the time taken.
+
+  `time` must be one of `:run` or `:real`.
+
+  `result-type` must be `integer` (which will return internal time units) or
+  `rational`/`single-float`/`double-float` (which will return seconds).
+
+  "
+  (with-gensyms (start end result)
+    `(let ((,start ,(ecase time
+                      (:run '(get-internal-run-time))
+                      (:real '(get-internal-real-time)))))
+       (progn ,@body)
+       (let* ((,end ,(ecase time
+                       (:run '(get-internal-run-time))
+                       (:real '(get-internal-real-time))))
+              (,result (- ,end ,start)))
+         ,(ecase result-type
+            (integer `,result)
+            (rational `(/ ,result internal-time-units-per-second))
+            (single-float `(coerce (/ ,result internal-time-units-per-second) 'single-float))
+            (double-float `(coerce (/ ,result internal-time-units-per-second) 'double-float)))))))
+
+
 (defmacro gimme (n &body body)
   `(iterate (repeat ,n)
      (collect (progn ,@body))))
--- a/src/gnuplot.lisp	Mon Jul 12 22:03:01 2021 -0400
+++ b/src/gnuplot.lisp	Wed Nov 10 21:13:00 2021 -0500
@@ -105,7 +105,7 @@
 
 
 ;;;; Convenience Wrappers -----------------------------------------------------
-(defun plot (data &key (style :linespoints) (file "plot.pdf"))
+(defun plot (data &key (style :linespoints) (file "plot.pdf") (logscale nil))
   "Plot `data` with gnuplot.
 
   Convenience wrapper around the gnuplot functions.  This is only intended for
@@ -116,8 +116,8 @@
   (with-gnuplot ()
     (gnuplot-data "$data" data)
     (gnuplot-format "set terminal pdfcairo size 10in, 8in
-                     set output '~A'
-                     plot $data using 1:2 with ~A"
-                    file
-                    (string-downcase (symbol-name style)))))
-
+                     set output '~A'"
+                    file)
+    (when logscale
+      (gnuplot-format "set logscale y"))
+    (gnuplot-format "plot $data using 1:2 with ~A" (string-downcase (symbol-name style)))))
--- a/src/iterate.lisp	Mon Jul 12 22:03:01 2021 -0400
+++ b/src/iterate.lisp	Wed Nov 10 21:13:00 2021 -0500
@@ -1112,3 +1112,77 @@
   "Sugar for `(if-first-iteration nil expr)`."
   `(if-first-iteration nil ,expr))
 
+
+(defmacro-clause (FOR vars WINDOW size ON sequence-or-length
+                  &optional START start END end)
+  "Iterate a window over a sequence.
+
+  The exact nature of the iteration depends on the form of `vars`:
+
+  If `vars` is a symbol, or a list of a single symbol, it will be bound to
+  a `size`-element `subseq` of `sequence-or-length` on each iteration.  In this
+  case, `sequence-or-length` must be a sequence.
+
+  If `vars` is a list of two symbols `(start end)`, they will be bound to the
+  start and end bounding indices of a a `size`-element window of
+  `sequence-or-length` on each iteration.  In this case, `sequence-or-length`
+  can be a sequence (in which case its `length` is used) or an integer.
+
+  If `vars` is a list of three symbols `(subseq start end)`, both of the above
+  bindings will happen.  In this case, `sequence-or-length` must be a sequence.
+
+  If `start` or `end` are given, they are used to restrict the range of the
+  sequence being iterated over.
+
+  `generate` is not supported at this time.
+
+  Examples:
+
+    (iterate (with string = \"abcdefg\")
+             (for x :window 2 :on string)
+             (collect x))
+    ; => (\"ab\" \"bc\" \"cd\" \"de\" \"ef\" \"fg\")
+
+    (iterate (with string = \"abcdefg\")
+             (for (start end) :window 2 :on 5)
+             (collect (subseq string start end)))
+    ; => (\"ab\" \"bc\" \"cd\" \"de\")
+
+    (iterate (with string = \"abcdefg\")
+             (for (x start end) :window 2 :on string)
+             (collect (list x start end)))
+    ; => ((\"ab\" 0 2) (\"bc\" 1 3) (\"cd\" 2 4) (\"de\" 3 5) (\"ef\" 4 6) (\"fg\" 5 7))
+
+    (iterate (with string = \"abcdefg\")
+             (for (x start end) :window 2 :on string :start 1 :end 5)
+             (collect (list x start end)))
+    ; => ((\"bc\" 1 3) (\"cd\" 2 4) (\"de\" 3 5))
+
+  "
+  (setf vars (ensure-list vars))
+  (alexandria:with-gensyms (n seq s)
+    (let (subseq% start% end%)
+      (ecase (length vars)
+        (1 (setf subseq% (first vars)
+                 start% (gensym "START")
+                 end% (gensym "END")))
+        (2 (setf subseq% nil
+                 start% (first vars)
+                 end% (second vars)))
+        (3 (setf subseq% (first vars)
+                 start% (second vars)
+                 end% (third vars))))
+      `(progn
+         (with ,s = ,(or start 0))
+         (with ,n = ,size)
+         (with ,seq = ,sequence-or-length)
+         (for ,start% :from ,s)
+         (for ,end% :from (+ ,n ,s) :to
+              ,(cond
+                 (end end)
+                 (subseq% `(length ,seq))
+                 (t `(etypecase ,seq
+                       (integer ,seq)
+                       (sequence (length ,seq))))))
+         ,@(when subseq%
+             `((for ,subseq% = (subseq ,seq ,start% ,end%))))))))
--- a/src/package.lisp	Mon Jul 12 22:03:01 2021 -0400
+++ b/src/package.lisp	Wed Nov 10 21:13:00 2021 -0500
@@ -19,6 +19,7 @@
 
 (defpackage :losh.base
   (:use :cl)
+  (:documentation "A few utilities re-exported from Alexandria, plus some other basic stuff.")
   (:import-from :alexandria
     :compose :curry :rcurry
     :with-gensyms :once-only
@@ -29,6 +30,8 @@
     :with-gensyms :once-only
     :ensure-list
 
+    :timing ; both profiling and iterate use this symbol
+
     :symb :mkstr))
 
 
@@ -346,6 +349,7 @@
     :unless-first-time
     :when-first-iteration
     :when-first-time
+    :window
     :within-radius
 
     ))
@@ -418,6 +422,7 @@
     :prl
     :shut-up
     :structural-string
+    :timing
 
     ))
 
@@ -453,6 +458,7 @@
 (defpackage-inheriting :losh
   (
 
+   :losh.base
    :losh.arrays
    :losh.bits
    :losh.chili-dogs
--- a/src/shell.lisp	Mon Jul 12 22:03:01 2021 -0400
+++ b/src/shell.lisp	Wed Nov 10 21:13:00 2021 -0500
@@ -10,8 +10,9 @@
   completes.  If false, it will return immediately and allow the program to run
   asynchronously.
 
-  `input` must be a character input stream, a string, or `nil`.  If non-`nil`
-  its contents will be sent to the program as its standard input.
+  `input` must be a character input stream, a string, a list of strings, or
+  `nil`.  If non-`nil` its contents will be sent to the program as its standard
+  input.  A list of strings will be sent separated by newlines.
 
   `result-type` must be one of:
 
@@ -31,6 +32,7 @@
   (ctypecase input
     (string (setf input (make-string-input-stream input)))
     (vector (setf input (flexi-streams:make-in-memory-input-stream input)))
+    (cons (setf input (make-string-input-stream (format nil "~{~A~^~%~}" input)))) ; todo make this not cons as much
     (stream)
     (null))
   (when (not wait)