提出 #24569066


ソースコード 拡げる

(in-package :cl-user)
(eval-when (:compile-toplevel :load-toplevel :execute)
  (defparameter *opt*
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0)))
  #+swank (ql:quickload '(:cl-debug-print :fiveam :cp/util) :silent t)
  #+swank (use-package :cp/util :cl-user)
  #-swank (set-dispatch-macro-character
           #\# #\> (lambda (s c p) (declare (ignore c p)) `(values ,(read s nil nil t))))
  #+sbcl (dolist (f '(:popcnt :sse4)) (pushnew f sb-c:*backend-subfeatures*))
  (setq *random-state* (make-random-state t)))
#-swank (eval-when (:compile-toplevel)
          (setq *break-on-signals* '(and warning (not style-warning))))
#+swank (set-dispatch-macro-character #\# #\> #'cl-debug-print:debug-print-reader)

(macrolet ((def (b)
             `(progn (deftype ,(intern (format nil "UINT~A" b)) () '(unsigned-byte ,b))
                     (deftype ,(intern (format nil "INT~A" b)) () '(signed-byte ,b))))
           (define-int-types (&rest bits) `(progn ,@(mapcar (lambda (b) `(def ,b)) bits))))
  (define-int-types 2 4 7 8 15 16 31 32 62 63 64))

(defconstant +mod+ 1000000007)

(defmacro dbg (&rest forms)
  (declare (ignorable forms))
  #+swank (if (= (length forms) 1)
              `(format *error-output* "~A => ~A~%" ',(car forms) ,(car forms))
              `(format *error-output* "~A => ~A~%" ',forms `(,,@forms))))

(declaim (inline println))
(defun println (obj &optional (stream *standard-output*))
  (let ((*read-default-float-format*
          (if (typep obj 'double-float) 'double-float *read-default-float-format*)))
    (prog1 (princ obj stream) (terpri stream))))

;; BEGIN_INSERTED_CONTENTS
(defpackage :cp/csc
  (:use :cl)
  (:export
   #:coo #:coo-m #:coo-n #:make-coo #:coo-insert!
   #:coo-rows #:coo-cols #:coo-values #:coo-nz
   #:csc #:make-csc #:csc-to-array #:make-csc-from-array #:make-csc-from-coo
   #:csc-gemv #:csc-gemv-with-basis #:csc-transpose #:csc-m #:csc-n #:csc-nz
   #:csc-colstarts #:csc-rows #:csc-values
   #:sparse-vector #:make-sparse-vector #:make-sparse-vector-from
   #:make-array-from-sparse-vector
   #:sparse-vector-nz #:sparse-vector-values #:sparse-vector-indices)
  (:documentation "Provides some representations of a sparse matrix."))
(in-package :cp/csc)

(deftype csc-float () 'rational)
(defconstant +zero+ (coerce 0 'csc-float))
(defconstant +one+ (coerce 1 'csc-float))

(defstruct (coo (:constructor %make-coo (m n nz rows cols values))
                (:copier nil)
                (:predicate nil))
  "Stores a sparse matrix with coordinate list representation (aka COO
format). Note that you can increase M and N after construction, but cannot
decrease them."
  (m nil :type (mod #.array-dimension-limit))
  (n nil :type (mod #.array-dimension-limit))
  (nz nil :type (mod #.array-dimension-limit))
  (rows nil :type (simple-array fixnum (*)))
  (cols nil :type (simple-array fixnum (*)))
  (values nil :type (simple-array csc-float (*))))

(defun make-coo (m n &optional (initial-size 4))
  (declare ((integer 1 (#.array-dimension-limit)) initial-size))
  (let ((initial-size (max 1 initial-size)))
    (%make-coo m n 0
               (make-array initial-size :element-type 'fixnum)
               (make-array initial-size :element-type 'fixnum)
               (make-array initial-size :element-type 'csc-float))))

(defun coo-insert! (coo row col value)
  "Destructively executes an assignment operation: COO[ROW][COL] := VALUE."
  (declare (optimize (speed 3))
           ((mod #.array-dimension-limit) row col))
  (assert (and (< row (coo-m coo))
               (< col (coo-n coo))))
  (symbol-macrolet ((rows (coo-rows coo))
                    (cols (coo-cols coo))
                    (values (coo-values coo))
                    (nz (coo-nz coo)))
    (when (= nz (length rows))
      (let ((new-size (max 1 (the (mod #.array-dimension-limit) (* 2 nz)))))
        (setq rows (adjust-array rows new-size)
              cols (adjust-array cols new-size)
              values (adjust-array values new-size))))
    (setf (aref rows nz) row
          (aref cols nz) col
          (aref values nz) value
          nz (+ nz 1))
    coo))

(defstruct (csc (:constructor make-csc (m n nz colstarts rows values))
                (:copier nil)
                (:predicate nil))
  "Stores a sparse matrix with compressed sparse column representation (aka CSC
format). Note that you can increase M after construction, but cannot decrease it
or change N."
  (m nil :type (mod #.array-dimension-limit))
  (n nil :type (mod #.array-dimension-limit))
  (nz nil :type (mod #.array-dimension-limit))
  (colstarts nil :type (simple-array fixnum (*)))
  (rows nil :type (simple-array fixnum (*)))
  (values nil :type (simple-array csc-float (*))))

(defun csc-to-array (csc &optional rowperm colperm)
  "Makes a 2-dimensional array from a CSC."
  (declare (optimize (speed 3))
           ((or null vector) rowperm colperm))
  (let* ((m (csc-m csc))
         (n (csc-n csc))
         (res (make-array (list m n) :element-type 'csc-float :initial-element +zero+))
         (colstarts (csc-colstarts csc))
         (rows (csc-rows csc))
         (values (csc-values csc)))
    (dotimes (col n)
      (let ((dest-col (if colperm (aref colperm col) col)))
        (loop for i from (aref colstarts col) below (aref colstarts (+ col 1))
              for row = (aref rows i)
              for dest-row = (if rowperm (aref rowperm row) row)
              for value = (aref values i)
              do (setf (aref res dest-row dest-col) value))))
    res))

(defun make-csc-from-array (array)
  "Makes a CSC from a 2-dimensional array."
  (declare (optimize (speed 3))
           ((array * (* *)) array))
  (destructuring-bind (m n) (array-dimensions array)
    (declare ((mod #.array-dimension-limit) m n))
    (let* ((colstarts (make-array (+ n 1) :element-type 'fixnum))
           (nz (count +zero+ (sb-ext:array-storage-vector array) :test-not #'=))
           (rows (make-array nz :element-type 'fixnum))
           (values (make-array nz :element-type 'csc-float))
           (end 0))
      (declare ((mod #.array-dimension-limit) end))
      (dotimes (col n)
        (setf (aref colstarts col) end)
        (dotimes (row m)
          (let ((value (aref array row col)))
            (unless (zerop value)
              (setf (aref rows end) row
                    (aref values end) value)
              (incf end)))))
      (setf (aref colstarts n) end)
      (make-csc m n nz colstarts rows values))))

(declaim (inline make-csc-from-coo))
(defun make-csc-from-coo (coo)
  "Makes a CSC from a COO. Note that the returned CSC contains zero when COO
contains it."
  (declare (optimize (speed 3))
           (inline stable-sort))
  (let* ((m (coo-m coo))
         (n (coo-n coo))
         (rows (coo-rows coo))
         (cols (coo-cols coo))
         (values (coo-values coo))
         (indices (let ((tmp (make-array (coo-nz coo) :element-type 'fixnum)))
                    (dotimes (i (length tmp))
                      (setf (aref tmp i) i))
                    (stable-sort tmp (lambda (i1 i2)
                                       (if (= (aref cols i1) (aref cols i2))
                                           (< (aref rows i1) (aref rows i2))
                                           (< (aref cols i1) (aref cols i2)))))))
         (nz 0))
    (declare ((simple-array fixnum (*)) indices)
             ((mod #.array-dimension-limit) nz))
    ;; drop duplicate elements
    (dotimes (i* (length indices))
      (let ((i (aref indices i*)))
        (if (and (> i* 0)
                 (let ((prev-i (aref indices (- i* 1))))
                   (and (= (aref rows i) (aref rows prev-i))
                        (= (aref cols i) (aref cols prev-i)))))
            (setf (aref indices (- nz 1)) i)
            (setf (aref indices nz) i
                  nz (+ nz 1)))))
    (let ((colstarts (make-array (+ n 1) :element-type 'fixnum))
          (csc-rows (make-array nz :element-type 'fixnum))
          (csc-values (make-array nz :element-type 'csc-float))
          (end 0)
          (prev-col -1))
      (declare ((mod #.array-dimension-limit) end)
               ((integer -1 (#.array-dimension-limit)) prev-col))
      (dotimes (i* nz)
        (let* ((i (aref indices i*))
               (row (aref rows i))
               (col (aref cols i))
               (value (aref values i)))
          (loop for j from col above prev-col
                do (setf (aref colstarts j) end))
          (setf (aref csc-rows end) row
                (aref csc-values end) value)
          (incf end)
          (setq prev-col col)))
      (loop for j from n above prev-col
            do (setf (aref colstarts j) end))
      (make-csc m n nz colstarts csc-rows csc-values))))

(declaim (inline csc-gemv-with-basis))
(defun csc-gemv-with-basis (csc vector basis)
  "Multiplies CSC and VECTOR and returns a resultant vector."
  (declare (vector vector basis))
  (let* ((m (csc-m csc))
         (colstarts (csc-colstarts csc))
         (rows (csc-rows csc))
         (values (csc-values csc))
         (res (make-array m :element-type 'csc-float :initial-element +zero+)))
    (dotimes (i m)
      (let ((bi (aref basis i)))
        (loop for k from (aref colstarts bi) below (aref colstarts (+ bi 1))
              do (incf (aref res (aref rows k))
                       (* (aref values k) (coerce (aref vector i) 'csc-float))))))
    res))

(declaim (inline csc-gemv))
(defun csc-gemv (csc vector)
  "Multiplies CSC and VECTOR and returns a resultant vector."
  (declare (vector vector))
  (let* ((m (csc-m csc))
         (n (length vector))
         (colstarts (csc-colstarts csc))
         (rows (csc-rows csc))
         (values (csc-values csc))
         (res (make-array m :element-type 'csc-float :initial-element +zero+)))
    (dotimes (j n)
      (loop for k from (aref colstarts j) below (aref colstarts (+ j 1))
            do (incf (aref res (aref rows k))
                     (* (aref values k) (coerce (aref vector j) 'csc-float)))))
    res))

(defun csc-transpose (csc)
  "Returns the transposed matrix of CSC. This function is non-destructive."
  (declare (optimize (speed 3)))
  (let* ((m (csc-m csc))
         (n (csc-n csc))
         (nz (csc-nz csc))
         (colstarts (csc-colstarts csc))
         (rows (csc-rows csc))
         (values (csc-values csc))
         (tmp (make-array m :element-type 'fixnum :initial-element 0))
         (new-colstarts (make-array (+ m 1) :element-type 'fixnum :initial-element 0))
         (new-rows (make-array nz :element-type 'fixnum :initial-element 0))
         (new-values (make-array nz :element-type 'csc-float :initial-element +zero+)))
    (dotimes (k nz)
      (let ((row (aref rows k)))
        (incf (aref tmp row))))
    ;; TMP[ROW] == the number of the elements in ROW
    (dotimes (i m)
      (setf (aref new-colstarts (+ i 1))
            (+ (aref new-colstarts i) (aref tmp i))))
    (fill tmp 0)
    (dotimes (j n)
      (loop for k from (aref colstarts j) below (aref colstarts (+ j 1))
            for row = (aref rows k)
            for new-pos = (+ (aref new-colstarts row) (aref tmp row))
            do (incf (aref tmp row))
               (setf (aref new-rows new-pos) j
                     (aref new-values new-pos) (aref values k))))
    (make-csc n m nz new-colstarts new-rows new-values)))

;; TODO: Should we store the intended dimension of vector?
(defstruct (sparse-vector (:constructor %make-sparse-vector (nz values indices)))
  (nz nil :type (mod #.array-dimension-limit))
  (values nil :type (simple-array csc-float (*)))
  (indices nil :type (simple-array fixnum (*))))

(defun make-sparse-vector (size)
  (%make-sparse-vector
   0
   (make-array size :element-type 'csc-float)
   (make-array size :element-type 'fixnum)))

(defun make-sparse-vector-from (vector)
  (declare (vector vector))
  (let* ((nz (count +zero+ vector :test-not #'=))
         (values (make-array nz :element-type 'csc-float))
         (indices (make-array nz :element-type 'fixnum))
         (end 0))
    (declare ((mod #.array-dimension-limit) end))
    (dotimes (i (length vector))
      (unless (zerop (aref vector i))
        (setf (aref values end) (aref vector i)
              (aref indices end) i)
        (incf end)))
    (%make-sparse-vector nz values indices)))

(defun make-array-from-sparse-vector (sparse-vector)
  (let* ((nz (sparse-vector-nz sparse-vector))
         (indices (sparse-vector-indices sparse-vector))
         (values (sparse-vector-values sparse-vector))
         (m (if (zerop (length indices))
                0
                (+ 1 (reduce #'max indices))))
         (res (make-array m :element-type 'csc-float :initial-element +zero+)))
    (dotimes (i nz)
      (let ((index (aref indices i))
            (value (aref values i)))
        (setf (aref res index) value)))
    res))

(defpackage :cp/extend-vector
  (:use :cl)
  (:export #:extend-vector #:extend-vectorf))
(in-package :cp/extend-vector)

(declaim (inline %power-of-two-ceiling))
(defun %power-of-two-ceiling (x)
  (ash 1 (integer-length (- x 1))))

(defun extend-vector (vector size &optional (initial-element nil supplied-p))
  (declare (optimize (speed 3))
           ((mod #.array-dimension-limit) size)
           (vector vector))
  (let ((new-size (%power-of-two-ceiling (max size 1))))
    (declare ((mod #.array-dimension-limit) new-size))
    (if (< (length vector) new-size)
        (if supplied-p
            (adjust-array vector new-size :initial-element initial-element)
            (adjust-array vector new-size))
        vector)))

(defconstant +not-supplied+ (if (boundp '+not-supplied+)
                                (symbol-value '+not-supplied+)
                                (make-symbol "NOT-SUPPLIED")))

(define-modify-macro extend-vectorf (new-size &optional (initial-element '+not-supplied+))
  (lambda (vector new-size initial-element)
    (declare ((mod #.array-dimension-limit) new-size))
    (if (< (length vector) new-size)
        (if (eq initial-element +not-supplied+)
            (extend-vector vector new-size)
            (extend-vector vector new-size initial-element))
        vector)))

(defpackage :cp/rdtscp
  (:use :cl :sb-assem)
  (:import-from :sb-c #:defknown #:define-vop #:move)
  (:import-from :sb-vm #:unsigned-reg #:rax-offset #:rdx-offset #:rcx-offset #:unsigned-num)
  (:export #:read-tsc)
  (:documentation "Provides a reader for time-stamp counter using RDTSCP
instruction."))
(in-package :cp/rdtscp)

(eval-when (:compile-toplevel :load-toplevel :execute)
  (when (find-package :sb-x86-64-asm)
    (sb-ext:unlock-package :sb-x86-64-asm)))

(defmacro emit-bytes (segment &rest bytes)
  `(progn ,@(mapcar (lambda (x) `(emit-byte ,segment ,x)) bytes)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (define-instruction rdtscp (segment)
    (:emitter (emit-bytes segment #x0f #x01 #xf9))))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defknown %read-tsc () (values (unsigned-byte 32) (unsigned-byte 32)) ()
    :overwrite-fndb-silently t)
  (define-vop (%read-tsc)
    (:policy :fast-safe)
    (:translate %read-tsc)
    (:temporary (:sc unsigned-reg :offset rax-offset :target lo) eax)
    (:temporary (:sc unsigned-reg :offset rdx-offset :target hi) edx)
    ;; RDTSCP instruction reads IA32_TSC_AUX value into ECX
    (:temporary (:sc unsigned-reg :offset rcx-offset) ecx)
    (:ignore ecx)
    (:results (hi :scs (unsigned-reg))
              (lo :scs (unsigned-reg)))
    (:result-types unsigned-num unsigned-num)
    (:generator 3
                (inst rdtscp)
                (move lo eax)
                (move hi edx))))

(declaim (inline read-tsc))
(defun read-tsc ()
  (multiple-value-bind (hi lo) (%read-tsc)
    (dpb hi (byte 32 32) lo)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (when (find-package :sb-x86-64-asm)
    (sb-ext:lock-package :sb-x86-64-asm)))

(defpackage :cp/iterset
  (:use :cl)
  (:export #:node-key #:iterset-empty-p #:iterset-first #:iterset-last #:iterset-insert
           #:make-iterset #:iterset-map #:node-next #:node-prev))
(in-package :cp/iterset)

(deftype key-type () 'fixnum)
(declaim (inline order))
(defun order (x y)
  (declare (key-type x y))
  (< x y))

(defstruct (node (:constructor %make-node (key priority &optional left right parent))
                 (:copier nil)
                 (:predicate nil)
                 (:conc-name %node-))
  (key nil :type key-type)
  (priority nil :type (integer 0 #.most-positive-fixnum))
  (left nil :type (or null node))
  (right nil :type (or null node))
  (parent nil :type (or null node)))

(declaim (inline node-key))
(defun node-key (node)
  (%node-key node))

(defstruct (iterset (:constructor make-iterset ())
                    (:copier nil)
                    (:predicate nil)
                    (:conc-name %iterset-))
  (root nil :type (or null node)))

(declaim (inline iterset-empty-p))
(defun iterset-empty-p (iterset)
  (null (%iterset-root iterset)))

(defun node-split (node key)
  "Destructively splits NODE with reference to KEY and returns two trees, the
smaller tree (< KEY) and the larger one (>= KEY)."
  (declare (optimize (speed 3)))
  (labels ((recur (node)
             (cond ((null node)
                    (values nil nil))
                   ((order (%node-key node) key)
                    (multiple-value-bind (left right)
                        (recur (%node-right node))
                      (when left
                        (setf (%node-parent left) node))
                      (setf (%node-right node) left)
                      (values node right)))
                   (t
                    (multiple-value-bind (left right)
                        (recur (%node-left node))
                      (when right
                        (setf (%node-parent right) node))
                      (setf (%node-left node) right)
                      (values left node))))))
    (recur node)))

(defun node-insert (node key)
  (declare (optimize (speed 3))
           ((or null node) node))
  "Destructively inserts KEY into NODE and returns the resultant tree. You
**cannot** rely on the side effect. Use the returned value. The behavior is
undefined when duplicate keys are inserted."
  (let ((new-node (%make-node key (random #.(+ 1 most-positive-fixnum)))))
    (labels ((recur (node)
               (cond ((null node) new-node)
                     ((> (%node-priority new-node) (%node-priority node))
                      (multiple-value-bind (left right)
                          (node-split node key)
                        (when left
                          (setf (%node-parent left) new-node))
                        (when right
                          (setf (%node-parent right) new-node))
                        (setf (%node-left new-node) left
                              (%node-right new-node) right)
                        new-node))
                     ((order key (%node-key node))
                      (let ((left (recur (%node-left node))))
                        (when left
                          (setf (%node-parent left) node))
                        (setf (%node-left node) left))
                      node)
                     (t
                      (let ((right (recur (%node-right node))))
                        (when right
                          (setf (%node-parent right) node))
                        (setf (%node-right node) right))
                      node))))
      (recur node))))

(defun iterset-insert (iterset key)
  "Destructively inserts KEY into ITERSET. You **can** rely on the side
effect. The behavior is undefined when duplicate keys are inserted."
  (setf (%iterset-root iterset)
        (node-insert (%iterset-root iterset) key))
  iterset)

(declaim (inline node-first))
(defun node-first (node)
  (declare (node node))
  (loop while (%node-left node)
        do (setq node (%node-left node)))
  node)

(declaim (inline iterset-first))
(defun iterset-first (iterset)
  "Returns the first **node** of ITERSET."
  (when (%iterset-root iterset)
    (node-first (%iterset-root iterset))))

(declaim (inline node-last))
(defun node-last (node)
  (declare (node node))
  (loop while (%node-right node)
        do (setq node (%node-right node)))
  node)

(declaim (inline iterset-last))
(defun iterset-last (iterset)
  "Returns the last **node** of ITERSET."
  (when (%iterset-root iterset)
    (node-last (%iterset-root iterset))))

(declaim (inline node-map))
(defun node-map (function node)
  "Successively applies FUNCTION to each key of NODE. FUNCTION must take one
argument."
  (declare (function function))
  (labels ((recur (node)
             (when node
               (recur (%node-left node))
               (funcall function (%node-key node))
               (recur (%node-right node)))))
    (recur node)))

(declaim (inline iterset-map))
(defun iterset-map (function iterset)
  "Successively applies FUNCTION to each key of ITERSET. FUNCTION must take one
argument."
  (node-map function (%iterset-root iterset)))

(defmethod print-object ((object node) stream)
  (print-unreadable-object (object stream :type t)
    (let ((init t))
      (node-map (lambda (key)
                  (if init
                      (setf init nil)
                      (write-char #\  stream))
                  (write key :stream stream))
                object))))

(defun node-next (node)
  "Returns the next node of NODE. Returns NIL instead if NODE is the last node."
  (declare (optimize (speed 3))
           (node node))
  (let ((key (%node-key node)))
    (if (%node-right node)
        (node-first (%node-right node))
        (loop while (%node-parent node)
              do (setq node (%node-parent node))
              when (order key (%node-key node))
              do (return node)
              finally (return nil)))))

(defun node-prev (node)
  "Returns the previous node of NODE. Returns NIL instead if NODE is the first
node."
  (declare (optimize (speed 3))
           (node node))
  (let ((key (%node-key node)))
    (if (%node-left node)
        (node-last (%node-left node))
        (loop while (%node-parent node)
              do (setq node (%node-parent node))
              when (order (%node-key node) key)
              do (return node)
              finally (return nil)))))

(defpackage :cp/movable-binary-heap
  (:use :cl)
  (:export #:make-heap #:heap-empty-error #:heap-pop
           #:heap-ensure-key #:heap-clear #:heap-peek #:heap-empty-p #:heap-count)
  (:documentation "Provides binary heap implementation with decrease-key and
increase-key operations."))
(in-package :cp/movable-binary-heap)

;; TODO: abstraction
;; NOTE: not tested

(declaim (inline compare))
(defun compare (x y)
  (declare (fixnum x y))
  (< x y))

(define-condition heap-empty-error (error)
  ((heap :initarg :heap :reader heap-empty-error-heap))
  (:report
   (lambda (condition stream)
     (format stream "Attempted to get an element from empty heap ~W"
             (heap-empty-error-heap condition)))))

(defstruct (heap
            (:constructor make-heap
                (size
                 &aux
                 (keys (make-array (+ 1 size) :element-type 'fixnum))
                 (priorities (make-array (+ 1 size) :element-type 'fixnum))
                 (positions (make-array (+ 1 size)
                                        :element-type 'fixnum
                                        :initial-element -1)))))
  (keys nil :type (simple-array fixnum (*)))
  (priorities nil :type (simple-array fixnum (*)))
  (positions nil :type (simple-array fixnum (*)))
  (end 1 :type (integer 1 (#.array-dimension-limit))))

(defun %heapify-up (heap pos)
  (declare (optimize (speed 3))
           ((mod #.array-dimension-limit) pos))
  (let* ((keys (heap-keys heap))
         (priorities (heap-priorities heap))
         (positions (heap-positions heap))
         (key (aref keys pos)))
    (labels ((recur (pos)
               (unless (= pos 1)
                 (let ((parent-pos (ash pos -1)))
                   (when (compare (aref priorities pos) (aref priorities parent-pos))
                     (rotatef (aref positions key) (aref positions (aref keys parent-pos)))
                     (rotatef (aref keys pos) (aref keys parent-pos))
                     (rotatef (aref priorities pos) (aref priorities parent-pos))
                     (recur parent-pos))))))
      (recur pos))))

(defun %heapify-down (heap pos)
  (declare (optimize (speed 3))
           ((mod #.array-dimension-limit) pos))
  (let* ((keys (heap-keys heap))
         (priorities (heap-priorities heap))
         (positions (heap-positions heap))
         (end (heap-end heap))
         (key (aref keys pos)))
    (labels
        ((recur (pos)
           (let* ((cpos1 (+ pos pos))
                  (cpos2 (+ 1 cpos1)))
             (declare ((mod #.array-dimension-limit) cpos1 cpos2))
             (when (< cpos1 end)
               (if (< cpos2 end)
                   (if (compare (aref priorities cpos1) (aref priorities cpos2))
                       (when (compare (aref priorities cpos1) (aref priorities pos))
                         (rotatef (aref positions key) (aref positions (aref keys cpos1)))
                         (rotatef (aref keys pos) (aref keys cpos1))
                         (rotatef (aref priorities pos) (aref priorities cpos1))
                         (recur cpos1))
                       (when (compare (aref priorities cpos2) (aref priorities pos))
                         (rotatef (aref positions key) (aref positions (aref keys cpos2)))
                         (rotatef (aref keys pos) (aref keys cpos2))
                         (rotatef (aref priorities pos) (aref priorities cpos2))
                         (recur cpos2)))
                   (when (compare (aref priorities cpos1) (aref priorities pos))
                     (rotatef (aref positions key) (aref positions (aref keys cpos1)))
                     (rotatef (aref keys pos) (aref keys cpos1))
                     (rotatef (aref priorities pos) (aref priorities cpos1))))))))
      (recur pos))))

(declaim #+sbcl (sb-ext:maybe-inline heap-ensure-key))
(defun heap-ensure-key (heap key priority &optional if-exists)
  "Adds KEY to HEAP if it doesn't exist and sets its priority to
PRIORITY. Otherwise updates its priority by IF-EXISTS."
  (declare (optimize (speed 3))
           ((mod #.array-dimension-limit) key))
  (symbol-macrolet ((end (heap-end heap)))
    (when (>= end (length (heap-keys heap)))
      (let ((new-size (min (* end 2) #.(- array-dimension-limit 1))))
        (setf (heap-keys heap) (adjust-array (heap-keys heap) new-size)
              (heap-priorities heap) (adjust-array (heap-priorities heap) new-size))))
    (let ((keys (heap-keys heap))
          (priorities (heap-priorities heap))
          (positions (heap-positions heap)))
      (let ((pos (aref positions key)))
        (if (= pos -1)
            (progn
              (setf (aref keys end) key
                    (aref priorities end) priority
                    (aref positions key) end)
              (%heapify-up heap end)
              (incf end))
            (let ((prev-priority (aref priorities pos)))
              (setf (aref priorities pos)
                    (if if-exists
                        (funcall if-exists prev-priority)
                        priority))
              (if (compare prev-priority (aref priorities pos))
                  (%heapify-down heap pos)
                  (%heapify-up heap pos)))))
      heap)))

(declaim #+sbcl (sb-ext:maybe-inline heap-pop))
(defun heap-pop (heap)
  "Deletes the topmost element of HEAP and returns its key and priority."
  (declare (optimize (speed 3)))
  (symbol-macrolet ((end (heap-end heap)))
    (let ((keys (heap-keys heap))
          (priorities (heap-priorities heap))
          (positions (heap-positions heap)))
      (when (= end 1)
        (error 'heap-empty-error :heap heap))
      (multiple-value-prog1 (values (aref keys 1) (aref priorities 1))
        (decf end)
        (setf (aref positions (aref keys 1)) -1)
        (unless (= end 1)
          (setf (aref keys 1) (aref keys end)
                (aref priorities 1) (aref priorities end)
                (aref positions (aref keys 1)) 1))
        (%heapify-down heap 1)))))

(declaim (inline heap-clear))
(defun heap-clear (heap)
  "Makes heap empty. Note that it takes linear time."
  (setf (heap-end heap) 1)
  (fill (heap-positions heap) -1)
  heap)

(declaim (inline heap-empty-p))
(defun heap-empty-p (heap)
  "Returns true iff HEAP is empty."
  (= 1 (heap-end heap)))

(declaim (inline heap-count))
(defun heap-count (heap)
  "Returns the current number of the elements in HEAP."
  (- (heap-end heap) 1))

(declaim (inline heap-peek))
(defun heap-peek (heap)
  "Returns the topmost element of HEAP, i.e. its key and priority."
  (if (= 1 (heap-end heap))
      (error 'heap-empty-error :heap heap)
      (values (aref (heap-keys heap) 1)
              (aref (heap-priorities heap) 1))))

(defpackage :cp/lud
  (:use :cl :cp/csc #:cp/movable-binary-heap #:cp/iterset #:cp/rdtscp #:cp/extend-vector)
  (:import-from :cp/csc #:csc-float #:+zero+ #:+one+)
  (:export #:lud #:lud-eta #:lu-factor
           #:lud-lower #:lud-upper #:lud-tlower #:lud-tupper #:lud-diagu
           #:lud-rank #:lud-colperm #:lud-icolperm #:lud-rowperm #:lud-irowperm #:lud-m
           #:make-lud-eta #:dense-solve! #:add-eta! #:lud-eta-lud #:lud-eta-count
           #:refactor #:refactor-p #:*refactor-threshold* #:*refactor-by-time*
           #:gauss-eta! #:gauss-eta-transposed!
           #:sparse-solve! #:sparse-solve-transposed!)
  (:documentation "Provides LU decomposition for sparse matrix. This module is
served for simplex method.

Reference:
Robert J. Vanderbei. Linear Programming: Foundations and Extensions. 5th edition."))
(in-package :cp/lud)

(defconstant +eps+ (coerce 0 'csc-float))
(defconstant +epsnum+ (coerce 0 'csc-float))

(defstruct (lud (:conc-name lud-))
  (m nil :type (mod #.array-dimension-limit))
  ;; lower triangular matrix
  (lower nil :type csc)
  ;; transposition of LOWER
  (tlower nil :type csc)
  ;; upper triangular matrix
  (upper nil :type csc)
  ;; transposition of UPPER
  (tupper nil :type csc)
  ;; diagonal elements of upper triagular matrix
  (diagu nil :type (simple-array csc-float (*)))
  (rank nil :type (mod #.array-dimension-limit))
  (colperm nil :type (simple-array fixnum (*)))
  (icolperm nil :type (simple-array fixnum (*)))
  (rowperm nil :type (simple-array fixnum (*)))
  (irowperm nil :type (simple-array fixnum (*))))

(defmacro vector-set* (vector index new-element)
  (let ((i (gensym))
        (elm (gensym)))
    `(let ((,i ,index)
           (,elm ,new-element))
       (extend-vectorf ,vector (+ 1 ,i))
       (setf (aref ,vector ,i) ,elm))))

(deftype ivec () '(simple-array fixnum (*)))
(deftype fvec () '(simple-array csc-float (*)))

(defconstant +nan+ -1)

(declaim (inline %power-of-two-ceiling))
(defun %power-of-two-ceiling (x)
  (ash 1 (integer-length (- x 1))))

(defun lu-factor (matrix basis)
  (declare (optimize (speed 3))
           (vector basis))
  ;; B: submatrix of MATRIX w.r.t. BASIS
  ;; BT: transposition of B
  (let* ((m (csc-m matrix))
         (colstarts (csc-colstarts matrix))
         (rows (csc-rows matrix))
         (values (csc-values matrix))
         (colperm (make-array m :element-type 'fixnum :initial-element 0))
         (icolperm (make-array m :element-type 'fixnum :initial-element +nan+))
         (rowperm (make-array m :element-type 'fixnum :initial-element 0))
         (irowperm (make-array m :element-type 'fixnum :initial-element +nan+))
         ;; the number of non-zero elements in each column
         (b-degs (make-array m :element-type 'fixnum :initial-element 0))
         (bt-degs (make-array m :element-type 'fixnum :initial-element 0))
         ;; HEAP keeps the column numbers in ascending order of degree.
         ;; Priority of col is M+1 iff B-DEGS[col] is zero;
         ;; Priority of col is M+2 iff col has no elements which are larger than +EPSNUM+.
         (heap (make-heap m))
         (tmp (make-array m :element-type 'fixnum :initial-element 0))
         (tmp2 (make-array m :element-type 'fixnum :initial-element +nan+)))
    (assert (= m (length basis)))
    (dotimes (i m)
      (let ((start (aref colstarts (aref basis i)))
            (end (aref colstarts (+ 1 (the fixnum (aref basis i))))))
        (declare ((mod #.array-dimension-limit) start end))
        (setf (aref b-degs i) (- end start))
        (loop for k from start below end
              do (incf (aref bt-degs (aref rows k))))))
    (let* ((estimated-nz (%power-of-two-ceiling
                          (ash (the fixnum (reduce #'+ b-degs)) -1)))
           (lower-colstarts (make-array (+ m 1) :element-type 'fixnum :initial-element 0))
           (lower-rows (make-array estimated-nz :element-type 'fixnum))
           (lower-values (make-array estimated-nz :element-type 'csc-float))
           (tupper-colstarts (make-array (+ m 1) :element-type 'fixnum :initial-element 0))
           (tupper-rows (make-array estimated-nz :element-type 'fixnum))
           (tupper-values (make-array estimated-nz :element-type 'csc-float))
           (diagu (make-array m :element-type 'csc-float))
           (b-indices (make-array m :element-type t))
           (b-values (make-array m :element-type t))
           (bt-indices (make-array m :element-type t))
           (bt-values (make-array m :element-type t))
           (rank m)
           (tag 1)
           (lower-nz 0)
           (upper-nz 0))
      (declare (ivec lower-rows tupper-rows)
               (fvec lower-values tupper-values)
               ((mod #.array-dimension-limit) rank tag lower-nz upper-nz))
      ;; initialize B and BT
      (dotimes (i m)
        (setf (aref b-indices i) (make-array (aref b-degs i) :element-type 'fixnum)
              (aref b-values i) (make-array (aref b-degs i) :element-type 'csc-float)
              (aref bt-indices i) (make-array (aref bt-degs i) :element-type 'fixnum)
              (aref bt-values i) (make-array (aref bt-degs i) :element-type 'csc-float)))
      (let ((bt-poses tmp))
        (dotimes (i m)
          (let ((bpos 0)
                (start (aref colstarts (aref basis i)))
                (end (aref colstarts (+ 1 (the fixnum (aref basis i))))))
            (declare ((mod #.array-dimension-limit) start end))
            (loop for k from start below end
                  for row = (aref rows k)
                  for bt-pos = (aref bt-poses row)
                  do (setf (aref (the ivec (aref b-indices i)) bpos) row
                           (aref (the fvec (aref b-values i)) bpos) (aref values k)
                           (aref (the ivec (aref bt-indices row)) bt-pos) i
                           (aref (the fvec (aref bt-values row)) bt-pos) (aref values k))
                     (incf (aref bt-poses row))
                     (incf bpos))))
        (fill bt-poses 0))
      ;; initialize heap
      (dotimes (j m)
        (heap-ensure-key heap j
                         (if (zerop (aref b-degs j)) (+ m 1) (aref b-degs j))))
      (block decomposition
        (dotimes (i m)
          (multiple-value-bind (pivot-col coldeg pivot-row rowdeg)
              (loop
                (multiple-value-bind (col priority) (heap-pop heap)
                  (when (> priority m)
                    ;; singular matrix
                    (when (= priority (+ m 1))
                      (assert (zerop (aref b-degs col))))
                    (setq rank i)
                    (return-from decomposition))
                  (let ((coldeg (aref b-degs col))
                        (rowdeg (+ m 1))
                        row)
                    ;; select row of minimal degree
                    (dotimes (k coldeg)
                      (when (and (< (aref bt-degs (aref (the ivec (aref b-indices col)) k))
                                    rowdeg)
                                 (> (abs (aref (the fvec (aref b-values col)) k))
                                    +epsnum+))
                        (setq row (aref (the ivec (aref b-indices col)) k)
                              rowdeg (aref bt-degs row))))
                    (when (< rowdeg (+ m 1))
                      (return (values col coldeg row rowdeg)))
                    ;; col has no elements which are sufficiently distant from zero
                    (heap-ensure-key heap col (+ m 2)))))
            (declare ((mod #.array-dimension-limit) pivot-col coldeg pivot-row rowdeg))
            (setf (aref colperm i) pivot-col
                  (aref icolperm pivot-col) i
                  (aref rowperm i) pivot-row
                  (aref irowperm pivot-row) i)
            ;; copy pivot column into LOWER and pivot row into TUPPER
            (setf (aref lower-colstarts (+ i 1))
                  (+ (aref lower-colstarts i) coldeg -1))
            (dotimes (k coldeg)
              (let ((row (aref (the ivec (aref b-indices pivot-col)) k))
                    (val (aref (the fvec (aref b-values pivot-col)) k)))
                (unless (= row pivot-row)
                  (vector-set* lower-rows lower-nz row)
                  (vector-set* lower-values lower-nz val)
                  (incf lower-nz))))
            (setf (aref tupper-colstarts (+ i 1))
                  (+ (aref tupper-colstarts i) rowdeg -1))
            (dotimes (k rowdeg)
              (let ((col (aref (the ivec (aref bt-indices pivot-row)) k))
                    (val (aref (the fvec (aref bt-values pivot-row)) k)))
                (if (= col pivot-col)
                    (setf (aref diagu i) val)
                    (progn
                      (vector-set* tupper-rows upper-nz col)
                      (vector-set* tupper-values upper-nz val)
                      (incf upper-nz)))))
            ;; remove pivot rows and element from B and BT
            (dotimes (k coldeg)
              (let ((row (aref (the ivec (aref b-indices pivot-col)) k)))
                (decf (aref bt-degs row))
                (let ((bt-pos 0))
                  (loop until (= pivot-col (aref (the ivec (aref bt-indices row)) bt-pos))
                        do (incf bt-pos))
                  (rotatef (aref (the ivec (aref bt-indices row)) bt-pos)
                           (aref (the ivec (aref bt-indices row)) (aref bt-degs row)))
                  (rotatef (aref (the fvec (aref bt-values row)) bt-pos)
                           (aref (the fvec (aref bt-values row)) (aref bt-degs row))))))
            (dotimes (k rowdeg)
              (let ((col (aref (the ivec (aref bt-indices pivot-row)) k)))
                (decf (aref b-degs col))
                (let ((b-pos 0))
                  (loop until (= pivot-row (aref (the ivec (aref b-indices col)) b-pos))
                        do (incf b-pos))
                  (rotatef (aref (the ivec (aref b-indices col)) b-pos)
                           (aref (the ivec (aref b-indices col)) (aref b-degs col)))
                  (rotatef (aref (the fvec (aref b-values col)) b-pos)
                           (aref (the fvec (aref b-values col)) (aref b-degs col))))))
            (setf (aref b-degs pivot-col) 0
                  (aref bt-degs pivot-row) 0)
            ;; update B and BT
            (loop
              with tags = tmp
              with bt-poses = tmp2
              for k from (aref lower-colstarts i) below (aref lower-colstarts (+ i 1))
              for row = (aref lower-rows k)
              do (dotimes (bt-pos (aref bt-degs row))
                   (setf (aref tags (aref (the ivec (aref bt-indices row)) bt-pos)) tag
                         (aref bt-poses (aref (the ivec (aref bt-indices row)) bt-pos)) bt-pos))
                 (loop
                   for kk from (aref tupper-colstarts i) below (aref tupper-colstarts (+ i 1))
                   for col = (aref tupper-rows kk)
                   for decr of-type csc-float = (/ (* (aref lower-values k)
                                                      (aref tupper-values kk))
                                                   (aref diagu i))
                   when (= (aref tags col) tag)
                   do (decf (aref (the fvec (aref bt-values row)) (aref bt-poses col))
                            decr)
                   else
                   do (let ((deg (aref bt-degs row)))
                        (vector-set* (the ivec (aref bt-indices row)) deg col)
                        (vector-set* (the fvec (aref bt-values row)) deg (- decr))
                        (incf (aref bt-degs row))))
                 (incf tag))
            (loop
              with tags = tmp
              with b-poses = tmp2
              for k from (aref tupper-colstarts i) below (aref tupper-colstarts (+ i 1))
              for col = (aref tupper-rows k)
              do (dotimes (b-pos (aref b-degs col))
                   (setf (aref tags (aref (the ivec (aref b-indices col)) b-pos)) tag
                         (aref b-poses (aref (the ivec (aref b-indices col)) b-pos)) b-pos))
                 (loop
                   for kk from (aref lower-colstarts i) below (aref lower-colstarts (+ i 1))
                   for row = (aref lower-rows kk)
                   for decr of-type csc-float = (/ (* (aref lower-values kk)
                                                      (aref tupper-values k))
                                                   (aref diagu i))
                   when (= (aref tags row) tag)
                   do (decf (aref (the fvec (aref b-values col)) (aref b-poses row))
                            decr)
                   else
                   do (let ((deg (aref b-degs col)))
                        (vector-set* (the ivec (aref b-indices col)) deg row)
                        (vector-set* (the fvec (aref b-values col)) deg (- decr))
                        (incf (aref b-degs col))))
                 (incf tag))
            (loop for k from (aref tupper-colstarts i) below (aref tupper-colstarts (+ i 1))
                  for col = (aref tupper-rows k)
                  do (heap-ensure-key heap col
                                      (if (zerop (aref b-degs col))
                                          (+ m 1)
                                          (aref b-degs col)))))))
      ;; fill dependent rows and cols
      (let ((end rank))
        (declare ((mod #.array-dimension-limit) end))
        (dotimes (col m)
          (when (= +nan+ (aref icolperm col))
            (setf (aref colperm end) col
                  (aref icolperm col) end
                  end (+ end 1)))))
      (let ((end rank))
        (declare ((mod #.array-dimension-limit) end))
        (dotimes (row m)
          (when (= +nan+ (aref irowperm row))
            (setf (aref rowperm end) row
                  (aref irowperm row) end
                  end (+ end 1)))))
      (loop for i from rank below m
            do (setf (aref lower-colstarts (+ i 1)) (aref lower-colstarts i)
                     (aref tupper-colstarts (+ i 1)) (aref tupper-colstarts i)
                     (aref diagu i) +zero+))
      (dotimes (k (aref lower-colstarts m))
        (setf (aref lower-rows k)
              (aref irowperm (aref lower-rows k))))
      (dotimes (k (aref tupper-colstarts m))
        (setf (aref tupper-rows k)
              (aref icolperm (aref tupper-rows k))))
      (dotimes (i m)
        (loop for k from (aref lower-colstarts i) below (aref lower-colstarts (+ i 1))
              do (setf (aref lower-values k)
                       (/ (aref lower-values k) (aref diagu i)))))
      (let* ((lower (make-csc m m lower-nz lower-colstarts lower-rows lower-values))
             (tupper (make-csc m m upper-nz tupper-colstarts tupper-rows tupper-values))
             (tlower (csc-transpose lower))
             (upper (csc-transpose tupper)))
        (make-lud :m m
                  :lower lower
                  :tlower tlower
                  :upper upper
                  :tupper tupper
                  :diagu diagu
                  :rank rank
                  :colperm colperm
                  :icolperm icolperm
                  :rowperm rowperm
                  :irowperm irowperm)))))

(defun dense-solve! (lud y)
  "Solves LUx = y and stores the solution to Y. The consequence is undefined
when it is infeasible."
  (declare (optimize (speed 3))
           (fvec y))
  (let* ((m (lud-m lud))
         (irowperm (lud-irowperm lud))
         (colperm (lud-colperm lud))
         (lower (lud-lower lud))
         (lower-colstarts (csc-colstarts lower))
         (lower-rows (csc-rows lower))
         (lower-values (csc-values lower))
         (tupper (lud-tupper lud))
         (tupper-colstarts (csc-colstarts tupper))
         (tupper-rows (csc-rows tupper))
         (tupper-values (csc-values tupper))
         (diagu (lud-diagu lud))
         (rank (lud-rank lud))
         (tmp (make-array m :element-type 'csc-float)))
    (dotimes (i m)
      (setf (aref tmp i) (aref y i)))
    (dotimes (i m)
      (setf (aref y (aref irowperm i)) (aref tmp i)))
    ;; y := L^(-1)y
    (dotimes (i rank)
      (let ((val (aref y i)))
        (loop for k from (aref lower-colstarts i) below (aref lower-colstarts (+ i 1))
              for row = (aref lower-rows k)
              do (decf (aref y row) (* (aref lower-values k) val)))))
    (loop for i from (- m 1) downto rank
          do (setf (aref y i) +zero+))
    (loop for i from (- rank 1) downto 0
          for val of-type csc-float = (aref y i)
          do (loop for k from (aref tupper-colstarts i) below (aref tupper-colstarts (+ i 1))
                   do (decf val (* (aref tupper-values k) (aref y (aref tupper-rows k)))))
             (setf (aref y i) (/ val (aref diagu i))))
    (dotimes (i m)
      (setf (aref tmp i) (aref y i)))
    (dotimes (i m)
      (setf (aref y (aref colperm i)) (aref tmp i)))
    y))

(defstruct (lud-eta (:constructor %make-lud-eta))
  (lud nil :type lud)
  (count 0 :type (mod #.array-dimension-limit))
  (nz 0 :type (mod #.array-dimension-limit))
  ;; This vector stores the leaving columns of each pivotting. Note that this
  ;; `column' doesn't mean the index of some variable but the column number of
  ;; the matrix B.
  (leaving-cols nil :type (simple-array fixnum (*)))
  (colstarts nil :type (simple-array fixnum (*)))
  (rows nil :type (simple-array fixnum (*)))
  (values nil :type (simple-array csc-float (*)))
  (cumtime 0 :type (unsigned-byte 64))
  (prev-cumtime 0 :type (unsigned-byte 64)))

(defun make-lud-eta (lud &key (initial-size 0) cumtime prev-cumtime)
  (declare ((or null (unsigned-byte 64)) cumtime prev-cumtime))
  (%make-lud-eta :lud lud
                 :leaving-cols (make-array 0 :element-type 'fixnum)
                 :colstarts (make-array 1 :element-type 'fixnum :initial-element 0)
                 :rows (make-array initial-size :element-type 'fixnum)
                 :values (make-array initial-size :element-type 'csc-float)
                 :cumtime (or cumtime 0)
                 :prev-cumtime (or prev-cumtime 0)))

(defun refactor (matrix basis)
  (let* ((start-time (read-tsc))
         (lud (lu-factor matrix basis))
         (timedelta (ldb (byte 64 0) (- (read-tsc) start-time))))
    (make-lud-eta lud :cumtime timedelta)))

(defun add-eta! (lud-eta leaving-col sparse-vector)
  (declare (optimize (speed 3)))
  (symbol-macrolet ((enz (lud-eta-nz lud-eta))
                    (ecount (lud-eta-count lud-eta))
                    (vector-nz (sparse-vector-nz sparse-vector))
                    (leaving-cols (lud-eta-leaving-cols lud-eta))
                    (colstarts (lud-eta-colstarts lud-eta))
                    (rows (lud-eta-rows lud-eta))
                    (values (lud-eta-values lud-eta)))
    (vector-set* leaving-cols ecount leaving-col)
    (loop for k from enz below (+ enz vector-nz)
          for pos across (sparse-vector-indices sparse-vector)
          for value of-type csc-float across (sparse-vector-values sparse-vector)
          do (vector-set* rows k pos)
             (vector-set* values k value))
    (incf ecount)
    (incf enz vector-nz)
    (vector-set* colstarts ecount enz)
    lud-eta))

(defmacro with-updating-time (lud-eta &body body)
  (let ((start-time (gensym "START"))
        (timedelta (gensym "DELTA"))
        (lude (gensym "LUDE")))
    `(let ((,start-time (read-tsc))
           (,lude ,lud-eta))
       (unwind-protect (progn ,@body)
         (let ((,timedelta (ldb (byte 64 0) (- (read-tsc) ,start-time))))
           (setf (lud-eta-cumtime ,lude)
                 (ldb (byte 64 0) (+ (lud-eta-cumtime ,lude) ,timedelta))))))))

(defconstant +initial-size+ 16
  "Is an initial size of temporary storage.")

(declaim (fvec *gauss-eta-values*)
         (ivec *gauss-eta-tags* *gauss-eta-rows*)
         ((integer 0 #.most-positive-fixnum) *gauss-eta-tag*))
(defparameter *gauss-eta-values* (make-array +initial-size+ :element-type 'csc-float))
(defparameter *gauss-eta-tags* (make-array +initial-size+ :element-type 'fixnum))
(defparameter *gauss-eta-tag* 1)
(defparameter *gauss-eta-rows* (make-array +initial-size+ :element-type 'fixnum))

(defun gauss-eta! (lud-eta xb)
  (declare (optimize (speed 3))
           (sparse-vector xb))
  (let* ((lud (lud-eta-lud lud-eta))
         (m (lud-m lud)))
    (extend-vectorf *gauss-eta-values* m)
    (extend-vectorf *gauss-eta-tags* m)
    (extend-vectorf *gauss-eta-rows* m))
  (with-updating-time lud-eta
    (let* ((vector-nz (sparse-vector-nz xb))
           (vector-values (sparse-vector-values xb))
           (vector-indices (sparse-vector-indices xb))
           (tmp-values *gauss-eta-values*)
           (tmp-tags *gauss-eta-tags*)
           (tmp-rows *gauss-eta-rows*)
           (tmp-end 0)
           (leaving-cols (lud-eta-leaving-cols lud-eta))
           (colstarts (lud-eta-colstarts lud-eta))
           (values (lud-eta-values lud-eta))
           (rows (lud-eta-rows lud-eta)))
      (declare (fvec tmp-values vector-values)
               (ivec tmp-rows tmp-tags vector-indices)
               ((mod #.array-dimension-limit) tmp-end))
      (when (zerop (lud-eta-count lud-eta))
        (return-from gauss-eta!))
      (labels ((add-to-tmp (nzpos value)
                 (setf (aref tmp-values nzpos) value
                       (aref tmp-tags nzpos) *gauss-eta-tag*
                       (aref tmp-rows tmp-end) nzpos)
                 (incf tmp-end)))
        (dotimes (k vector-nz)
          (add-to-tmp (aref vector-indices k) (aref vector-values k)))
        (dotimes (j (lud-eta-count lud-eta))
          (let ((leaving-col (aref leaving-cols j))
                leaving-col-k)
            (loop for k from (aref colstarts j) below (aref colstarts (+ j 1))
                  for row = (aref rows k)
                  unless (= (aref tmp-tags row) *gauss-eta-tag*)
                  do (add-to-tmp row +zero+)
                  when (= row leaving-col)
                  do (setq leaving-col-k k))
            (let ((coef (/ (aref tmp-values leaving-col) (aref values leaving-col-k))))
              (unless (zerop coef)
                (loop for k from (aref colstarts j) below leaving-col-k
                      for row = (aref rows k)
                      do (decf (aref tmp-values row) (* (aref values k) coef)))
                (setf (aref tmp-values leaving-col) coef)
                (loop for k from (+ leaving-col-k 1) below (aref colstarts (+ j 1))
                      for row = (aref rows k)
                      do (decf (aref tmp-values row) (* (aref values k) coef)))))))
        (let ((nz 0))
          (dotimes (k tmp-end)
            (let ((row (aref tmp-rows k)))
              (when (> (abs (aref tmp-values row)) +eps+)
                (vector-set* vector-values nz (aref tmp-values row))
                (vector-set* vector-indices nz row)
                (incf nz))))
          (setf (sparse-vector-values xb) vector-values
                (sparse-vector-indices xb) vector-indices
                (sparse-vector-nz xb) nz))
        (incf *gauss-eta-tag*)
        xb))))

(defun gauss-eta-transposed! (lud-eta xb)
  (declare (optimize (speed 3)))
  (let* ((lud (lud-eta-lud lud-eta))
         (m (lud-m lud)))
    (extend-vectorf *gauss-eta-values* m)
    (extend-vectorf *gauss-eta-tags* m))
  (with-updating-time lud-eta
    (let* ((vector-nz (sparse-vector-nz xb))
           (vector-values (sparse-vector-values xb))
           (vector-indices (sparse-vector-indices xb))
           (tmp-values *gauss-eta-values*)
           (tmp-tags *gauss-eta-tags*)
           (leaving-cols (lud-eta-leaving-cols lud-eta))
           (colstarts (lud-eta-colstarts lud-eta))
           (values (lud-eta-values lud-eta))
           (rows (lud-eta-rows lud-eta)))
      (declare (fvec tmp-values vector-values)
               (ivec tmp-tags vector-indices))
      (loop for j from (- (lud-eta-count lud-eta) 1) downto 0
            for leaving-col = (aref leaving-cols j)
            for leaving-col-k = nil
            do (dotimes (k vector-nz)
                 (let ((row (aref vector-indices k)))
                   (when (= row leaving-col)
                     (setq leaving-col-k k))
                   (setf (aref tmp-values row) (aref vector-values k)
                         (aref tmp-tags row) *gauss-eta-tag*)))
               (unless (= *gauss-eta-tag* (aref tmp-tags leaving-col))
                 (vector-set* vector-values vector-nz +zero+)
                 (vector-set* vector-indices vector-nz leaving-col)
                 (setq leaving-col-k vector-nz)
                 (incf vector-nz)
                 (setf (aref tmp-values leaving-col) +zero+
                       (aref tmp-tags leaving-col) *gauss-eta-tag*))
               (let ((tmp (aref vector-values leaving-col-k))
                     leaving-col-eta-k)
                 (declare (csc-float tmp))
                 (loop for k from (aref colstarts j) below (aref colstarts (+ j 1))
                       for row = (aref rows k)
                       when (= row leaving-col)
                       do (setq leaving-col-eta-k k)
                       when (and (= (aref tmp-tags row) *gauss-eta-tag*)
                                 (/= row leaving-col))
                       do (decf tmp (* (aref values k) (aref tmp-values row))))
                 (incf *gauss-eta-tag*)
                 (setf (aref vector-values leaving-col-k)
                       (/ tmp (aref values leaving-col-eta-k)))))
      (setf (sparse-vector-values xb) vector-values
            (sparse-vector-indices xb) vector-indices
            (sparse-vector-nz xb) vector-nz)
      xb)))

(declaim (fvec *sparse-solve-values*)
         (ivec *sparse-solve-tags* *sparse-solve-rows*)
         ((integer 0 #.most-positive-fixnum) *sparse-solve-tag*))
(defparameter *sparse-solve-values* (make-array +initial-size+ :element-type 'csc-float))
(defparameter *sparse-solve-tags* (make-array +initial-size+ :element-type 'fixnum))
(defparameter *sparse-solve-tag* 1)

(defun sparse-solve! (lud-eta y)
  (declare (optimize (speed 3)))
  (let* ((lud (lud-eta-lud lud-eta))
         (m (lud-m lud)))
    (extend-vectorf *sparse-solve-values* m)
    (extend-vectorf *sparse-solve-tags* m))
  (with-updating-time lud-eta
    (let* ((lud (lud-eta-lud lud-eta))
           (rank (lud-rank lud))
           (vector-nz (sparse-vector-nz y))
           (vector-indices (sparse-vector-indices y))
           (vector-values (sparse-vector-values y))
           (tree (make-iterset))
           ;; vector values sorted w.r.t. the order of LU decomposition
           (tmp-values *sparse-solve-values*)
           (tmp-tags *sparse-solve-tags*)
           (tag *sparse-solve-tag*))
      (declare (fvec tmp-values vector-values)
               (ivec tmp-tags vector-indices))
      (labels ((add-to-tmp (lu-pos value)
                 (setf (aref tmp-values lu-pos) value
                       (aref tmp-tags lu-pos) tag)
                 (iterset-insert tree lu-pos)))
        (let ((irowperm (lud-irowperm lud)))
          (dotimes (k vector-nz)
            (let ((lu-pos (aref irowperm (aref vector-indices k))))
              (add-to-tmp lu-pos (aref vector-values k)))))
        ;; y := L^(-1)y
        (let* ((lower (lud-lower lud))
               (lower-colstarts (csc-colstarts lower))
               (lower-rows (csc-rows lower))
               (lower-values (csc-values lower))
               (node (iterset-first tree)))
          (loop while (and node (< (node-key node) rank))
                for lu-pos = (node-key node)
                for beta of-type csc-float = (aref tmp-values lu-pos)
                for start = (aref lower-colstarts lu-pos)
                for end = (aref lower-colstarts (+ lu-pos 1))
                do (loop for k from start below end 
                         for row = (aref lower-rows k)
                         unless (= (aref tmp-tags row) tag)
                         do (add-to-tmp row +zero+)
                         do (decf (aref tmp-values row) (* (aref lower-values k) beta)))
                   (setq node (node-next node))))
        ;; fill free variable
        ;; y := U^(-1)y
        (let* ((upper (lud-upper lud))
               (upper-colstarts (csc-colstarts upper))
               (upper-rows (csc-rows upper))
               (upper-values (csc-values upper))
               (diagu (lud-diagu lud))
               (node (iterset-last tree)))
          (loop while (and node (>= (node-key node) rank))
                for lu-pos = (node-key node)
                do (setf (aref tmp-values lu-pos) +zero+)
                   (setq node (node-prev node)))
          (loop while node
                for lu-pos = (node-key node)
                for beta of-type csc-float = (/ (aref tmp-values lu-pos) (aref diagu lu-pos))
                for start = (aref upper-colstarts lu-pos)
                for end = (aref upper-colstarts (+ lu-pos 1))
                do (loop for k from start below end
                         for row = (aref upper-rows k)
                         unless (= (aref tmp-tags row) tag)
                         do (add-to-tmp row +zero+)
                         do (decf (aref tmp-values row) (* (aref upper-values k) beta)))
                   (setf (aref tmp-values lu-pos) beta)
                   (setq node (node-prev node)))))
      ;; update y
      (let ((nz 0)
            (node (iterset-first tree))
            (colperm (lud-colperm lud)))
        (declare ((mod #.array-dimension-limit) nz))
        (loop while node
              for lu-pos = (node-key node)
              when (> (abs (aref tmp-values lu-pos)) +eps+)
              do (vector-set* vector-values nz (aref tmp-values lu-pos))
                 (vector-set* vector-indices nz (aref colperm lu-pos))
                 (incf nz)
              do (setq node (node-next node)))
        (setf (sparse-vector-nz y) nz
              (sparse-vector-indices y) vector-indices
              (sparse-vector-values y) vector-values))
      (gauss-eta! lud-eta y)
      (incf *sparse-solve-tag*)
      y)))

(defun sparse-solve-transposed! (lud-eta y)
  (declare (optimize (speed 3)))
  (let* ((lud (lud-eta-lud lud-eta))
         (m (lud-m lud)))
    (extend-vectorf *sparse-solve-values* m)
    (extend-vectorf *sparse-solve-tags* m))
  (with-updating-time lud-eta
    (gauss-eta-transposed! lud-eta y)
    (let* ((lud (lud-eta-lud lud-eta))
           (rank (lud-rank lud))
           (vector-nz (sparse-vector-nz y))
           (vector-indices (sparse-vector-indices y))
           (vector-values (sparse-vector-values y))
           (tree (make-iterset))
           ;; vector values sorted w.r.t. the order of LU decomposition
           (tmp-values *sparse-solve-values*)
           (tmp-tags *sparse-solve-tags*)
           (tag *sparse-solve-tag*))
      (declare (fvec tmp-values vector-values)
               (ivec tmp-tags vector-indices))
      (labels ((add-to-tmp (lu-pos value)
                 (setf (aref tmp-values lu-pos) value
                       (aref tmp-tags lu-pos) tag)
                 (iterset-insert tree lu-pos)))
        (let ((icolperm (lud-icolperm lud)))
          (dotimes (k vector-nz)
            (let ((lu-pos (aref icolperm (aref vector-indices k))))
              (add-to-tmp lu-pos (aref vector-values k)))))
        ;; y := U^(-T)y
        (let* ((tupper (lud-tupper lud))
               (tupper-colstarts (csc-colstarts tupper))
               (tupper-rows (csc-rows tupper))
               (tupper-values (csc-values tupper))
               (diagu (lud-diagu lud))
               (node (iterset-first tree)))
          (loop while (and node (< (node-key node) rank))
                for lu-pos = (node-key node)
                for beta of-type csc-float = (/ (aref tmp-values lu-pos) (aref diagu lu-pos))
                for start = (aref tupper-colstarts lu-pos)
                for end = (aref tupper-colstarts (+ 1 lu-pos))
                do (loop for k from start below end 
                         for row = (aref tupper-rows k)
                         unless (= (aref tmp-tags row) tag)
                         do (add-to-tmp row +zero+)
                         do (decf (aref tmp-values row) (* (aref tupper-values k) beta)))
                   (setf (aref tmp-values lu-pos) beta)
                   (setq node (node-next node))))
        ;; fill free varaiable
        ;; y := L^(-T)y
        (let* ((tlower (lud-tlower lud))
               (tlower-colstarts (csc-colstarts tlower))
               (tlower-rows (csc-rows tlower))
               (tlower-values (csc-values tlower))
               (node (iterset-last tree)))
          (loop while (and node (>= (node-key node) rank))
                for lu-pos = (node-key node)
                do (setf (aref tmp-values lu-pos) +zero+)
                   (setq node (node-prev node)))
          (loop while node
                for lu-pos = (node-key node)
                for beta of-type csc-float = (aref tmp-values lu-pos)
                for start = (aref tlower-colstarts lu-pos)
                for end = (aref tlower-colstarts (+ lu-pos 1))
                do (loop for k from start below end
                         for row = (aref tlower-rows k)
                         unless (= (aref tmp-tags row) tag)
                         do (add-to-tmp row +zero+)
                         do (decf (aref tmp-values row) (* (aref tlower-values k) beta)))
                   (setq node (node-prev node)))))
      ;; update y
      (let ((nz 0)
            (node (iterset-first tree))
            (rowperm (lud-rowperm lud)))
        (declare ((mod #.array-dimension-limit) nz))
        (loop while node
              for lu-pos = (node-key node)
              when (> (abs (aref tmp-values lu-pos)) +eps+)
              do (vector-set* vector-values nz (aref tmp-values lu-pos))
                 (vector-set* vector-indices nz (aref rowperm lu-pos))
                 (incf nz)
              do (setq node (node-next node)))
        (setf (sparse-vector-nz y) nz
              (sparse-vector-indices y) vector-indices
              (sparse-vector-values y) vector-values))
      (incf *sparse-solve-tag*)
      ;; #>y
      y)))

(declaim ((integer 0 #.most-positive-fixnum) *refactor-threshold*))
(defparameter *refactor-threshold* 100)
(defparameter *refactor-by-time* t)

(defun refactor-p (lud-eta leaving-col)
  (declare (optimize (speed 3))
           ((mod #.array-dimension-limit) leaving-col))
  (let ((count (lud-eta-count lud-eta))
        (colstarts (lud-eta-colstarts lud-eta))
        (rows (lud-eta-rows lud-eta)))
    (assert (> count 0))
    (prog1 (or (>= count *refactor-threshold*)
               ;; leaving column vanishes at the last E
               (loop for k from (aref colstarts (- count 1)) below (aref colstarts count)
                     never (= (aref rows k) leaving-col))
               (and *refactor-by-time*
                    (>= count 2)
                    (>= (floor (lud-eta-cumtime lud-eta) count)
                        (floor (lud-eta-prev-cumtime lud-eta) (- count 1)))))
      (setf (lud-eta-prev-cumtime lud-eta)
            (lud-eta-cumtime lud-eta)))))

(defpackage :cp/sparse-simplex
  (:use :cl :cp/csc :cp/lud)
  (:import-from :cp/csc #:+zero+ #:+one+ #:csc-float)
  (:import-from :cp/lud #:vector-set* #:extend-vectorf)
  (:use :cl)
  (:export #:make-dictionary #:make-sparse-lp #:slp-restore
           #:slp-lude #:slp-m #:slp-n #:slp-dictionary
           #:slp-mat #:slp-tmat #:slp-b #:slp-c #:slp-x-basic #:slp-y-nonbasic
           #:correct-x-basic! #:correct-y-nonbasic!
           #:dictionary-basics #:dictionary-nonbasics #:dictionary-basic-flag
           #:slp-primal! #:slp-dual! #:slp-dual-primal! #:slp-self-dual!)
  (:documentation
   "Provides two kinds of simplex method for sparse LP:

- two-phase (dual-then-primal) simplex method using Dantzig's pivot rule;
- TODO: parametric self-dual simplex method.

Usage procedure:
1. MAKE-SPARSE-LP
2. SPARSE-DUAL-PRIMAL!
3. SRARSE-LP-RESTORE

Reference:
Robert J. Vanderbei. Linear Programming: Foundations and Extensions. 5th edition."))
(in-package :cp/sparse-simplex)

(defconstant +eps-large+ 0)
(defconstant +eps-middle+ 0)
(defconstant +eps-small+ 0)
(defconstant +inf+ most-positive-fixnum)
(defconstant +neg-inf+ most-negative-fixnum)

(defun add-slack! (a)
  (declare (optimize (speed 3))
           (csc a))
  (symbol-macrolet ((m (csc-m a))
                    (n (csc-n a))
                    (colstarts (csc-colstarts a))
                    (rows (csc-rows a))
                    (values (csc-values a))
                    (nz (csc-nz a)))
    ;; Add slack variable
    (loop for row below m
          for col of-type (mod #.array-dimension-limit) from n
          for k from (aref colstarts n)
          do (vector-set* values k +one+)
             (vector-set* rows k row)
             (vector-set* colstarts (+ col 1) (+ k 1))
             (incf nz)
          finally (setf n (+ n m)))
    a))

(defstruct (dictionary (:constructor %make-dictionary))
  (m nil :type (mod #.array-dimension-limit))
  (n nil :type (mod #.array-dimension-limit))
  (basics nil :type (simple-array fixnum (*)))
  (nonbasics nil :type (simple-array fixnum (*)))
  (basic-flag nil :type (simple-array fixnum (*))))

(defconstant +nan+ most-positive-fixnum)
(defun make-dictionary (m n basics)
  "BASICS[i] = column number of the constraints matrix (of size m * (n + m))
which is currently basic.

0, 1, 2, ....., n-1, n, n+1, ..., n+m-1
|- non-slack vars -| |-- slack vars --|
"
  (declare (optimize (speed 3))
           (vector basics)
           ((mod #.array-dimension-limit) m n))
  (assert (= m (length basics)))
  (let* ((basics (coerce basics '(simple-array fixnum (*))))
         (basic-flag (make-array (+ n m) :element-type 'fixnum :initial-element +nan+))
         (nonbasics (make-array n :element-type 'fixnum)))
    (dotimes (i m)
      (let ((col (aref basics i)))
        (setf (aref basic-flag col) i)))
    (let ((j 0))
      (dotimes (col (length basic-flag))
        (when (= (aref basic-flag col) +nan+)
          (setf (aref nonbasics j) col
                (aref basic-flag col) (lognot j))
          (incf j))))
    (%make-dictionary :m m :n n :basics basics :nonbasics nonbasics :basic-flag basic-flag)))

(defun dictionary-swap! (dictionary col-out col-in)
  (declare (optimize (speed 3))
           ((mod #.array-dimension-limit) col-out col-in))
  (let* ((basics (dictionary-basics dictionary))
         (nonbasics (dictionary-nonbasics dictionary))
         (basic-flag (dictionary-basic-flag dictionary))
         (i (aref basics col-out))
         (j (aref nonbasics col-in)))
    (setf (aref basics col-out) j
          (aref nonbasics col-in) i
          (aref basic-flag i) (lognot col-in)
          (aref basic-flag j) col-out))
  dictionary)

(declaim (ftype (function * (values csc-float &optional)) dot*))
(defun dot* (coefs x-basic basics)
  (declare (optimize (speed 3))
           ((simple-array csc-float (*)) coefs x-basic)
           ((simple-array fixnum (*)) basics))
  (let ((res +zero+))
    (declare (csc-float res))
    (dotimes (i (length x-basic))
      (incf res (* (aref coefs (aref basics i)) (aref x-basic i))))
    res))

(defconstant +initial-size+ 16)

(declaim ((simple-array csc-float (*)) *tmp-values*)
         ((simple-array fixnum (*)) *tmp-tags* *tmp-rows*)
         ((integer 0 #.most-positive-fixnum) *tmp-tag*))
(defparameter *tmp-values*
  (make-array +initial-size+ :element-type 'csc-float))
(defparameter *tmp-tags*
  (make-array +initial-size+ :element-type 'fixnum :initial-element 0))
(defparameter *tmp-tag* 1)
(defparameter *tmp-rows* (make-array +initial-size+ :element-type 'fixnum))

(defun tmat-times-vec! (tmat vec basic-flag &optional res)
  (declare (optimize (speed 3))
           (csc tmat)
           (sparse-vector vec)
           ((or null sparse-vector) res)
           ((simple-array fixnum (*)) basic-flag))
  (let ((m (csc-m tmat)))
    (extend-vectorf *tmp-values* m)
    (extend-vectorf *tmp-tags* m)
    (extend-vectorf *tmp-rows* m))
  (let ((tmp-values *tmp-values*)
        (tmp-tags *tmp-tags*)
        (tag *tmp-tag*)
        (tmp-rows *tmp-rows*)
        (vector-indices (sparse-vector-indices vec))
        (vector-values (sparse-vector-values vec))
        (tmat-values (csc-values tmat))
        (tmat-colstarts (csc-colstarts tmat))
        (tmat-rows (csc-rows tmat))
        (end 0))
    (declare ((mod #.array-dimension-limit)))
    (dotimes (k1 (sparse-vector-nz vec))
      (let ((col (aref vector-indices k1)))
        (loop for k2 from (aref tmat-colstarts col) below (aref tmat-colstarts (+ col 1))
              for row = (aref tmat-rows k2)
              when (< (aref basic-flag row) 0)
              do (unless (eql tag (aref tmp-tags row))
                   (setf (aref tmp-values row) +zero+
                         (aref tmp-tags row) tag
                         (aref tmp-rows end) row
                         end (+ end 1)))
                 (incf (aref tmp-values row)
                       (* (aref vector-values k1) (aref tmat-values k2))))))
    (let* ((res (or res (make-sparse-vector end)))
           (res-values (sparse-vector-values res))
           (res-indices (sparse-vector-indices res))
           (nz 0))
      (declare ((simple-array csc-float (*)) res-values)
               ((simple-array fixnum (*)) res-indices)
               ((mod #.array-dimension-limit) nz))
      (extend-vectorf res-values end)
      (extend-vectorf res-indices end)
      (dotimes (k end)
        (let ((row (aref tmp-rows k)))
          (when (> (abs (aref tmp-values row)) +eps-large+)
            (setf (aref res-values nz) (aref tmp-values row)
                  (aref res-indices nz) (lognot (aref basic-flag row))
                  nz (+ nz 1)))))
      (setf (sparse-vector-values res) res-values
            (sparse-vector-indices res) res-indices
            (sparse-vector-nz res) nz)
      (incf *tmp-tag*)
      res)))

(defstruct (sparse-lp (:constructor %make-sparse-lp)
                      (:conc-name slp-))
  (m nil :type (mod #.array-dimension-limit))
  (n nil :type (mod #.array-dimension-limit))
  (mat nil :type csc)
  (tmat nil :type csc)
  (b nil :type (simple-array csc-float (*)))
  (c nil :type (simple-array csc-float (*)))
  (x-basic nil :type (simple-array csc-float (*)))
  (y-nonbasic nil :type (simple-array csc-float (*)))
  (dictionary nil :type dictionary)
  (lude nil :type lud-eta))

(defun correct-x-basic! (lude x-basic)
  (assert (zerop (lud-eta-count lude)))
  (dense-solve! (lud-eta-lud lude) x-basic))

(defun correct-y-nonbasic! (sparse-lp)
  (declare (optimize (speed 3)))
  (let* ((lude (slp-lude sparse-lp))
         (m (slp-m sparse-lp))
         (n (slp-n sparse-lp))
         (tmat (slp-tmat sparse-lp))
         (c (slp-c sparse-lp))
         (tmp (make-sparse-vector m))
         (dictionary (slp-dictionary sparse-lp))
         (basics (dictionary-basics dictionary))
         (nonbasics (dictionary-nonbasics dictionary))
         (basic-flag (dictionary-basic-flag dictionary))
         (y-nonbasic (slp-y-nonbasic sparse-lp))
         (tmp-values (sparse-vector-values tmp))
         (tmp-indices (sparse-vector-indices tmp)))
    (symbol-macrolet ((tmp-nz (sparse-vector-nz tmp)))
      (dotimes (i m)
        (let ((coef (aref c (aref basics i))))
          (when (> (abs coef) +eps-large+)
            (setf (aref tmp-values tmp-nz) coef
                  (aref tmp-indices tmp-nz) i)
            (incf tmp-nz))))
      (sparse-solve-transposed! lude tmp)
      (let* ((tmp (tmat-times-vec! tmat tmp basic-flag))
             (tmp-values (sparse-vector-values tmp))
             (tmp-indices (sparse-vector-indices tmp)))
        (dotimes (j n)
          (setf (aref y-nonbasic j) (- (aref c (aref nonbasics j)))))
        (dotimes (k (sparse-vector-nz tmp))
          (incf (aref y-nonbasic (aref tmp-indices k)) (aref tmp-values k)))))
    sparse-lp))

(defun make-sparse-lp (a b c &key (add-slack t) (dictionary nil supplied-p))
  "Creates SPARSE-LP from a sparse matrix, which has the standard form: maximize
c'x subject to Ax <= b, x >= 0.

This function translates a given LP to an equality form Ax + w = b by adding
slack variables and changes A to (A E). If you want to give an equality form
directly, just disable ADD-SLACK.

You can set DICTIONARY to an arbitrary initial dictionary, but please note that
the consequence is undefined when it is rank-deficient."
  (declare (optimize (speed 3))
           (csc a)
           ((simple-array csc-float (*)) b c))
  (let* ((m (csc-m a))
         (n (if add-slack (csc-n a) (- (csc-n a) (csc-m a)))))
    (assert (= m (length b)))
    (when add-slack
      (setq a (add-slack! a)))
    ;; Add coefficients for basic variables
    (unless (= (length c) (+ m n))
      (assert (= n (length c)))
      (setq c (adjust-array c (the (mod #.array-dimension-limit) (+ n m))
                            :initial-element +zero+)))
    (let* ((x-basic (make-array m :element-type 'csc-float))
           (y-nonbasic (make-array n :element-type 'csc-float))
           (dictionary (or dictionary
                           (let ((basics (make-array m :element-type 'fixnum)))
                             (dotimes (i m)
                               (setf (aref basics i) (+ n i)))
                             (make-dictionary m n basics))))
           (basics (dictionary-basics dictionary))
           (a-transposed (csc-transpose a)))
      (unless supplied-p
        (dotimes (j n)
          (setf (aref y-nonbasic j) (- (aref c j)))))
      (dotimes (i m)
        (setf (aref x-basic i) (aref b i)))
      (let* ((lude (refactor a basics))
             (slp (%make-sparse-lp :m m :n n
                                   :mat a :tmat a-transposed
                                   :b b :c c
                                   :x-basic x-basic
                                   :y-nonbasic y-nonbasic
                                   :dictionary dictionary
                                   :lude lude)))
        (when supplied-p
          (correct-x-basic! lude x-basic)
          (correct-y-nonbasic! slp))
        slp))))

(defun slp-restore (sparse-lp)
  "Restores the current solution of LP and returns five values: objective value,
primal solution, dual solution, values of primal slack variables, and values of
dual slack variables. (Note that they are not necessarily feasible solutions if
the current dictionary is not feasible.)"
  (declare (optimize (speed 3)))
  (let* ((m (slp-m sparse-lp))
         (n (slp-n sparse-lp))
         (c (slp-c sparse-lp))
         (x-basic (slp-x-basic sparse-lp))
         (y-nonbasic (slp-y-nonbasic sparse-lp))
         (dictionary (slp-dictionary sparse-lp))
         (basics (dictionary-basics dictionary))
         (nonbasics (dictionary-nonbasics dictionary))
         (x (make-array (+ n m) :element-type 'csc-float :initial-element +zero+))
         (y (make-array (+ n m) :element-type 'csc-float :initial-element +zero+)))
    (dotimes (i m)
      (setf (aref x (aref basics i)) (aref x-basic i)))
    (dotimes (i n)
      (setf (aref y (aref nonbasics i)) (aref y-nonbasic i)))
    (values (dot* c x-basic basics)
            (subseq x 0 n)
            (subseq y n)
            (subseq x n)
            (subseq y 0 n))))

(defun pick-negative (vector)
  (declare (optimize (speed 3))
           ((simple-array csc-float (*)) vector))
  (let ((min (- +eps-small+))
        res)
    (dotimes (i (length vector))
      (when (< (aref vector i) min)
        (setq min (aref vector i)
              res i)))
    res))

(defun ratio-test (x dx)
  (declare (optimize (speed 3))
           ((simple-array csc-float (*)) x)
           (sparse-vector dx))
  (let ((min +inf+)
        (dx-indices (sparse-vector-indices dx))
        (dx-values (sparse-vector-values dx))
        res)
    (dotimes (k (sparse-vector-nz dx))
      (when (> (aref dx-values k) +eps-large+)
        (let* ((index (aref dx-indices k))
               (rate (/ (aref x index) (aref dx-values k))))
          (when (< rate min)
            (setq min rate
                  res index)))))
    res))

(defun slp-primal! (sparse-lp)
  "Applies primal simplex method to SPARSE-LP and returns the terminal state:
:optimal or :unbounded."
  (declare (optimize (speed 3)))
  (let* ((m (slp-m sparse-lp))
         (n (slp-n sparse-lp))
         (x-basic (slp-x-basic sparse-lp))
         (y-nonbasic (slp-y-nonbasic sparse-lp))
         (dictionary (slp-dictionary sparse-lp))
         (basics (dictionary-basics dictionary))
         (nonbasics (dictionary-nonbasics dictionary))
         (basic-flag (dictionary-basic-flag dictionary))
         (mat (slp-mat sparse-lp))
         (tmat (slp-tmat sparse-lp))
         (dx (make-sparse-vector m))
         (dy (make-sparse-vector n))
         (tmp (make-sparse-vector m)))
    (symbol-macrolet ((lude (slp-lude sparse-lp))
                      (dx-values (sparse-vector-values dx))
                      (dx-indices (sparse-vector-indices dx))
                      (dx-nz (sparse-vector-nz dx))
                      (dy-values (sparse-vector-values dy))
                      (dy-indices (sparse-vector-indices dy))
                      (dy-nz (sparse-vector-nz dy))
                      (tmp-values (sparse-vector-values tmp))
                      (tmp-indices (sparse-vector-indices tmp))
                      (tmp-nz (sparse-vector-nz tmp)))
      (loop
        ;; find entering column
        (let* ((col-in (pick-negative y-nonbasic)))
          (unless col-in
            (return :optimal))
          ;; dx_B := B^(-1)Ne_j (j = col-in)
          (let ((acolstarts (csc-colstarts mat))
                (arows (csc-rows mat))
                (avalues (csc-values mat))
                (j (aref nonbasics col-in)))
            (loop for i from 0
                  for k from (aref acolstarts j) below (aref acolstarts (+ j 1))
                  do (setf (aref dx-values i) (aref avalues k)
                           (aref dx-indices i) (aref arows k))
                  finally (setq dx-nz i)))
          (sparse-solve! lude dx)
          ;; find leaving column
          (let ((col-out (ratio-test x-basic dx)))
            (unless col-out
              (return :unbounded))
            ;; dy_N := -(B^(-1)N)^Te_i (i = col-out)
            (setf (aref tmp-values 0) (- +one+)
                  (aref tmp-indices 0) col-out
                  tmp-nz 1)
            (sparse-solve-transposed! lude tmp)
            (tmat-times-vec! tmat tmp basic-flag dy)
            ;; t := x_i/dx_i
            ;; s := y_j/dy_j
            (let ((rate-t (loop for k below dx-nz
                                when (= (aref dx-indices k) col-out)
                                do (return (/ (aref x-basic col-out)
                                              (aref dx-values k)))
                                finally (error "Huh?")))
                  (rate-s (loop for k below dy-nz
                                when (= (aref dy-indices k) col-in)
                                do (return (/ (aref y-nonbasic col-in)
                                              (aref dy-values k)))
                                finally (error "Huh?"))))
              ;; y_N := y_N - s dy_N
              ;; y_i := s
              ;; x_B := x_B - t dx_B
              ;; x_j := t
              (dotimes (k dy-nz)
                (let ((j (aref dy-indices k)))
                  (decf (aref y-nonbasic j) (* rate-s (aref dy-values k)))))
              (setf (aref y-nonbasic col-in) rate-s)
              (dotimes (k dx-nz)
                (let ((i (aref dx-indices k)))
                  (decf (aref x-basic i) (* rate-t (aref dx-values k)))))
              (setf (aref x-basic col-out) rate-t)
              ;; Update basis
              (dictionary-swap! dictionary col-out col-in)
              (add-eta! lude col-out dx)
              (when (refactor-p lude col-out)
                (setq lude (refactor mat basics))))))))))

(defun slp-dual! (sparse-lp)
  "Applies dual simplex method to SPARSE-LP and returns the terminal state:
:optimal or :infeasible."
  (declare (optimize (speed 3)))
  (let* ((m (slp-m sparse-lp))
         (n (slp-n sparse-lp))
         (x-basic (slp-x-basic sparse-lp))
         (y-nonbasic (slp-y-nonbasic sparse-lp))
         (dictionary (slp-dictionary sparse-lp))
         (basics (dictionary-basics dictionary))
         (nonbasics (dictionary-nonbasics dictionary))
         (basic-flag (dictionary-basic-flag dictionary))
         (mat (slp-mat sparse-lp))
         (tmat (slp-tmat sparse-lp))
         (dx (make-sparse-vector m))
         (dy (make-sparse-vector n))
         (tmp (make-sparse-vector m)))
    (symbol-macrolet ((lude (slp-lude sparse-lp))
                      (dx-values (sparse-vector-values dx))
                      (dx-indices (sparse-vector-indices dx))
                      (dx-nz (sparse-vector-nz dx))
                      (dy-values (sparse-vector-values dy))
                      (dy-indices (sparse-vector-indices dy))
                      (dy-nz (sparse-vector-nz dy))
                      (tmp-values (sparse-vector-values tmp))
                      (tmp-indices (sparse-vector-indices tmp))
                      (tmp-nz (sparse-vector-nz tmp)))
      (loop
        ;; find leaving column
        (let ((col-out (pick-negative x-basic)))
          (unless col-out
            (return :optimal))
          ;; dy_N := -(B^(-1)N)^Te_i (i = col-out)
          (setf (aref tmp-values 0) (- +one+)
                (aref tmp-indices 0) col-out
                tmp-nz 1)
          (sparse-solve-transposed! lude tmp)
          (tmat-times-vec! tmat tmp basic-flag dy)
          ;; find entering column
          (let ((col-in (ratio-test y-nonbasic dy)))
            (unless col-in
              (return :infeasible))
            ;; dx_B := B^(-1)Ne_j (j = col-in)
            (let ((acolstarts (csc-colstarts mat))
                  (arows (csc-rows mat))
                  (avalues (csc-values mat))
                  (j (aref nonbasics col-in)))
              (loop for i from 0
                    for k from (aref acolstarts j) below (aref acolstarts (+ j 1))
                    do (setf (aref dx-values i) (aref avalues k)
                             (aref dx-indices i) (aref arows k))
                    finally (setq dx-nz i)))
            (sparse-solve! lude dx)
            ;; t := x_i/dx_i
            ;; s := y_j/dy_j
            (let ((rate-t (loop for k below dx-nz
                                when (= (aref dx-indices k) col-out)
                                do (return (/ (aref x-basic col-out)
                                              (aref dx-values k)))
                                finally (error "Huh?")))
                  (rate-s (loop for k below dy-nz
                                when (= (aref dy-indices k) col-in)
                                do (return (/ (aref y-nonbasic col-in)
                                              (aref dy-values k)))
                                finally (error "Huh?"))))
              ;; y_N := y_N - s dy_N
              ;; y_i := s
              ;; x_B := x_B - t dx_B
              ;; x_j := t
              (dotimes (k dy-nz)
                (let ((j (aref dy-indices k)))
                  (decf (aref y-nonbasic j) (* rate-s (aref dy-values k)))))
              (setf (aref y-nonbasic col-in) rate-s)
              (dotimes (k dx-nz)
                (let ((i (aref dx-indices k)))
                  (decf (aref x-basic i) (* rate-t (aref dx-values k)))))
              (setf (aref x-basic col-out) rate-t)
              ;; Update basis
              (dictionary-swap! dictionary col-out col-in)
              (add-eta! lude col-out dx)
              (when (refactor-p lude col-out)
                (setq lude (refactor mat basics))))))))))

(defun slp-dual-primal! (sparse-lp)
  "Applies two-phase simplex method to SPARSE-LP and returns the terminal state:
:optimal, :unbounded, or :infeasible. "
  (declare (optimize (speed 3)))
  (let* ((n (slp-n sparse-lp))
         (dictionary (slp-dictionary sparse-lp))
         (nonbasics (dictionary-nonbasics dictionary))
         (y-nonbasic (slp-y-nonbasic sparse-lp))
         (c (slp-c sparse-lp)))
    ;; Set all the coefficiets of objective to negative values.
    (dotimes (j n)
      (let ((col (aref nonbasics j)))
        (setf (aref y-nonbasic j)
              (+ (max (if (< col n) (aref c col) +zero+) +one+)
                 (random +one+)))))
    (let ((state-dual (slp-dual! sparse-lp)))
      (correct-y-nonbasic! sparse-lp)
      (unless (eql state-dual :optimal)
        (return-from slp-dual-primal! state-dual))
      (slp-primal! sparse-lp))))

;;;
;;; self-dual simplex method
;;;

(defun self-dual-ratio-test (x dx mu x-params)
  (declare (optimize (speed 3))
           ((simple-array csc-float (*)) x x-params)
           (sparse-vector dx)
           (csc-float mu))
  (let ((min +inf+)
        (dx-indices (sparse-vector-indices dx))
        (dx-values (sparse-vector-values dx))
        res)
    (dotimes (k (sparse-vector-nz dx))
      (when (> (aref dx-values k) +eps-large+)
        (let* ((index (aref dx-indices k))
               (rate (/ (+ (aref x index) (* mu (aref x-params index)))
                        (aref dx-values k))))
          (when (< rate min)
            (setq min rate
                  res index)))))
    res))

;; not tested
(defun slp-self-dual! (sparse-lp)
  "Applies self-dual simplex method to SPARSE-LP and returns the terminal state:
:optimal, :infeasible, or :dual-infeasible."
  (declare (optimize (speed 3)))
  (let* ((m (slp-m sparse-lp))
         (n (slp-n sparse-lp))
         (x-basic (slp-x-basic sparse-lp))
         (y-nonbasic (slp-y-nonbasic sparse-lp))
         (dictionary (slp-dictionary sparse-lp))
         (basics (dictionary-basics dictionary))
         (nonbasics (dictionary-nonbasics dictionary))
         (basic-flag (dictionary-basic-flag dictionary))
         (mat (slp-mat sparse-lp))
         (tmat (slp-tmat sparse-lp))
         (dx (make-sparse-vector m))
         (dy (make-sparse-vector n))
         (tmp (make-sparse-vector m))
         (x-params (make-array n :element-type 'csc-float :initial-element +zero+))
         (y-params (make-array m :element-type 'csc-float :initial-element +zero+)))
    (symbol-macrolet ((lude (slp-lude sparse-lp))
                      (dx-values (sparse-vector-values dx))
                      (dx-indices (sparse-vector-indices dx))
                      (dx-nz (sparse-vector-nz dx))
                      (dy-values (sparse-vector-values dy))
                      (dy-indices (sparse-vector-indices dy))
                      (dy-nz (sparse-vector-nz dy))
                      (tmp-values (sparse-vector-values tmp))
                      (tmp-indices (sparse-vector-indices tmp))
                      (tmp-nz (sparse-vector-nz tmp)))
      ;; initialize parameters for x and y
      (dotimes (j n)
        (let ((colstarts (csc-colstarts mat))
              (rows (csc-rows mat))
              (values (csc-values mat)))
          (loop for k from (aref colstarts j) below (aref colstarts (+ j 1))
                for a2 of-type csc-float = (expt (aref values k) 2)
                do (incf (aref x-params (aref rows k)) a2)
                   (incf (aref y-params j) a2))))
      (map-into x-params
                (lambda (x) (+ (random 1d0) (sqrt (the (double-float 0d0) x))))
                x-params)
      (map-into y-params
                (lambda (x) (+ (random 1d0) (sqrt (the (double-float 0d0) x))))
                y-params)
      (loop
        (let ((mu +neg-inf+)
              col-in
              col-out)
          (dotimes (j n)
            (when (and (> (aref y-params j) +eps-small+)
                       (< mu (/ (- (aref y-nonbasic j)) (aref y-params j))))
              (setq mu (/ (- (aref y-nonbasic j)) (aref y-params j))
                    col-in j)))
          (dotimes (i m)
            (when (and (> (aref x-params i) +eps-small+)
                       (< mu (/ (- (aref x-basic i)) (aref x-params i))))
              (setq mu (/ (- (aref x-basic i)) (aref x-params i))
                    col-out i)))
          (when (<= mu +eps-middle+)
            (return :optimal))
          (assert (or (and col-in (not col-out))
                      (and (not col-in) col-out)))
          (when col-out
            ;; dy_N := -(B^(-1)N)^T e_i where i is leaving column
            (setf (aref tmp-values 0) (- +one+)
                  (aref tmp-indices 0) col-out
                  tmp-nz 1)
            (sparse-solve-transposed! lude tmp)
            (tmat-times-vec! tmat tmp basic-flag dy)
            (let ((col-in (self-dual-ratio-test y-nonbasic dy mu y-params)))
              (unless col-in
                (return :infeasible))
              ;; dx_B := B^(-1)Ne_j where j is entering column
              (let* ((j (aref nonbasics col-in))
                     (colstarts (csc-colstarts mat))
                     (rows (csc-rows mat))
                     (values (csc-values mat))
                     (start (aref colstarts j))
                     (end (aref colstarts (+ j 1))))
                (loop for k from start below end
                      for i of-type (mod #.array-dimension-limit) = (- k start)
                      do (setf (aref dx-values i) (aref values k)
                               (aref dx-indices i) (aref rows k)))
                (setq dx-nz (- end start))
                (sparse-solve! lude dx))))
          (when col-in
            ;; dx_B := B^(-1)Ne_j where j is entering column
            (let* ((j (aref nonbasics col-in))
                   (colstarts (csc-colstarts mat))
                   (rows (csc-rows mat))
                   (values (csc-values mat))
                   (start (aref colstarts j))
                   (end (aref colstarts (+ j 1))))
              (loop for k from start below end
                    for i of-type (mod #.array-dimension-limit) = (- k start)
                    do (setf (aref dx-values i) (aref values k)
                             (aref dx-indices i) (aref rows k)))
              (setq dx-nz (- end start))
              (sparse-solve! lude dx)
              (let ((col-out (self-dual-ratio-test x-basic dx mu x-params)))
                (unless col-out
                  (return :dual-infeasible))
                ;; dy_N := -(B^(-1)N)^T e_i where i is leaving column
                (setf (aref tmp-values 0) (- +one+)
                      (aref tmp-indices 0) col-out
                      tmp-nz 1)
                (sparse-solve-transposed! lude tmp)
                (tmat-times-vec! tmat tmp basic-flag dy))))
          ;; t := x_i/dx_i
          ;; tparam := xparam_i/dx_i
          ;; s := y_j/dy_j
          ;; sparam := y_param_j/dy_j
          (multiple-value-bind (rate-t rate-tparam)
              (dotimes (k dx-nz (error "Huh?"))
                (when (= (aref dx-indices k) col-out)
                  (return (values (/ (aref x-basic col-out)
                                     (aref dx-values k))
                                  (/ (aref x-params col-out)
                                     (aref dx-values k))))))
            (multiple-value-bind (rate-s rate-sparam)
                (dotimes (k dy-nz (error "Huh?"))
                  (when (= (aref dy-indices k) col-in)
                    (return (values (/ (aref y-nonbasic col-in)
                                       (aref dy-values k))
                                    (/ (aref y-params col-in)
                                       (aref dy-values k))))))
              ;; y_N := y_N - s dy_N
              ;; yparam := yparam - s dy_N
              ;; y_i := s
              ;; x_B := x_B - t dx_B
              ;; xparam_B := xparam - t dx_B
              ;; x_j := t
              (dotimes (k dy-nz)
                (let ((j (aref dy-indices k)))
                  (decf (aref y-nonbasic j) (* rate-s (aref dy-values k)))
                  (decf (aref y-params j) (* rate-sparam (aref dy-values k)))))
              (setf (aref y-nonbasic col-in) rate-s
                    (aref y-params col-in) rate-sparam)
              (dotimes (k dx-nz)
                (let ((i (aref dx-indices k)))
                  (decf (aref x-basic i) (* rate-t (aref dx-values k)))
                  (decf (aref x-params i) (* rate-tparam (aref dx-values k)))))
              (setf (aref x-basic col-out) rate-t
                    (aref x-params col-out) rate-tparam)
              ;; Update basis
              (dictionary-swap! dictionary col-out col-in)
              (add-eta! lude col-out dx)
              (when (refactor-p lude col-out)
                (setq lude (refactor mat basics))))))))))

(defpackage :cp/read-fixnum
  (:use :cl)
  (:export #:read-fixnum))
(in-package :cp/read-fixnum)

(declaim (ftype (function * (values fixnum &optional)) read-fixnum))
(defun read-fixnum (&optional (in *standard-input*))
  "NOTE: cannot read -2^62"
  (macrolet ((%read-byte ()
               `(the (unsigned-byte 8)
                     #+swank (char-code (read-char in nil #\Nul))
                     #-swank (sb-impl::ansi-stream-read-byte in nil #.(char-code #\Nul) nil))))
    (let* ((minus nil)
           (result (loop (let ((byte (%read-byte)))
                           (cond ((<= 48 byte 57)
                                  (return (- byte 48)))
                                 ((zerop byte) ; #\Nul
                                  (error "Read EOF or #\Nul."))
                                 ((= byte #.(char-code #\-))
                                  (setq minus t)))))))
      (declare ((integer 0 #.most-positive-fixnum) result))
      (loop
        (let* ((byte (%read-byte)))
          (if (<= 48 byte 57)
              (setq result (+ (- byte 48)
                              (* 10 (the (integer 0 #.(floor most-positive-fixnum 10))
                                         result))))
              (return (if minus (- result) result))))))))

;; BEGIN_USE_PACKAGE
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/read-fixnum :cl-user))
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/sparse-simplex :cl-user))
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/csc :cl-user))
(in-package :cl-user)

;;;
;;; Body
;;;

(defun main ()
  (let* ((n (read))
         (coo (make-coo (+ 1 (* 3 (- n 1))) (* 3 (- n 1))))
         (as (make-array n :element-type 'uint62 :initial-element 0))
         (bs (make-array n :element-type 'uint62 :initial-element 0))
         (coefs (make-array (* 3 (- n 1)) :element-type 'rational :initial-element 0))
         (rhs (make-array (+ 1 (* 3 (- n 1))) :element-type 'rational :initial-element 0)))
    (dotimes (i n)
      (setf (aref as i) (read-fixnum)))
    (dotimes (i n)
      (setf (aref bs i) (read-fixnum)))
    (labels ((%getvar (index op)
               (ecase op
                 (:y+ index)
                 (:y- (+ index n -1))
                 (:z (+ index (* 2 (- n 1)))))))
      (let ((row 0))
        (dotimes (i n)
          (when (< i (- n 1))
            (coo-insert! coo row (%getvar i :y+) 1)
            (coo-insert! coo row (%getvar i :y-) -1))
          (when (>= (- i 1) 0)
            (coo-insert! coo row (%getvar (- i 1) :y+) -1)
            (coo-insert! coo row (%getvar (- i 1) :y-) 1))
          (setf (aref rhs row) (- (aref as i) (aref bs i)))
          ;; #>(csc-to-array (make-csc-from-coo coo))
          (incf row))
        
        ;; #>row
        (dotimes (i (- n 1))
          (coo-insert! coo row (%getvar i :y+) 1)
          (coo-insert! coo row (%getvar i :y-) -1)
          (coo-insert! coo row (%getvar i :z) -1)
          (incf row)
          (coo-insert! coo row (%getvar i :y+) -1)
          (coo-insert! coo row (%getvar i :y-) 1)
          (coo-insert! coo row (%getvar i :z) -1)
          (incf row))
        (dotimes (i (- n 1))
          (setf (aref coefs (%getvar i :z)) -1))
        ;; #>row
        )
      ;; #>rhs
      (let* ((csc (make-csc-from-coo coo))
             ;; (mat (csc-to-array csc))
             (lp (make-sparse-lp csc rhs coefs)))
        ;; #>mat
        (slp-dual-primal! lp)
        (println (- (slp-restore lp)))))))

#-swank (main)

;;;
;;; Test
;;;

#+swank
(progn
  (defparameter *lisp-file-pathname* (uiop:current-lisp-file-pathname))
  (setq *default-pathname-defaults* (uiop:pathname-directory-pathname *lisp-file-pathname*))
  (uiop:chdir *default-pathname-defaults*)
  (defparameter *dat-pathname* (uiop:merge-pathnames* "test.dat" *lisp-file-pathname*))
  (defparameter *problem-url* "https://atcoder.jp/contests/kupc2016/tasks/kupc2016_h"))

#+swank
(defun gen-dat ()
  (uiop:with-output-file (out *dat-pathname* :if-exists :supersede)
    (format out "")))

#+swank
(defun bench (&optional (out (make-broadcast-stream)))
  (time (run *dat-pathname* out)))

#+(and sbcl (not swank))
(eval-when (:compile-toplevel)
  (when sb-c::*undefined-warnings*
    (error "undefined warnings: ~{~A~^ ~}" sb-c::*undefined-warnings*)))

;; To run: (5am:run! :sample)
#+swank
(5am:test :sample
  (5am:is
   (equal "2
"
          (run "2
1 5
3 1
" nil)))
  (5am:is
   (equal "6
"
          (run "5
1 2 3 4 5
3 3 1 1 1
" nil)))
  (5am:is
   (equal "48
"
          (run "27
46 3 4 2 10 2 5 2 6 7 20 13 9 49 3 8 4 3 19 9 3 5 4 13 9 5 7
10 2 5 6 2 6 3 2 2 5 3 11 13 2 2 7 7 3 9 5 13 4 17 2 2 2 4
" nil)))
  (5am:is
   (equal "6302172
"
          (run "18
3878348 423911 8031742 1035156 24256 10344593 19379 3867285 4481365 1475384 1959412 1383457 164869 4633165 6674637 9732852 10459147 2810788
1236501 770807 4003004 131688 1965412 266841 3980782 565060 816313 192940 541896 250801 217586 3806049 1220252 1161079 31168 2008961
" nil)))
  (5am:is
   (equal "1234567890
"
          (run "2
1 99999999999
1234567891 1
" nil))))

提出情報

提出日時
問題 H - 壁壁壁壁壁壁壁
ユーザ sansaqua
言語 Common Lisp (SBCL 2.0.3)
得点 60
コード長 99250 Byte
結果 TLE
実行時間 2218 ms
メモリ 518712 KiB

コンパイルエラー

; file: /imojudge/sandbox/Main.lisp
; in: DEFUN CSC-TO-ARRAY
;     (AREF CP/CSC::COLPERM CP/CSC::COL)
; ==>
;   (SB-KERNEL:HAIRY-DATA-VECTOR-REF/CHECK-BOUNDS ARRAY SB-INT:INDEX)
; 
; note: unable to
;   optimize
; because:
;   Upgraded element type of array is not known at compile time.

;     (AREF CP/CSC::ROWPERM CP/CSC::ROW)
; ==>
;   (SB-KERNEL:HAIRY-DATA-VECTOR-REF/CHECK-BOUNDS ARRAY SB-INT:INDEX)
; 
; note: unable to
;   optimize
; because:
;   Upgraded element type of array is not known at compile time.

;     (MAKE-ARRAY (LIST CP/CSC::M CP/CSC::N) :ELEMENT-TYPE 'CP/CSC::CSC-FLOAT
;                 :INITIAL-ELEMENT CP/CSC::+ZERO+)
; --> LET* THE 
; ==>
;   (* #:D0 #:D1)
; 
; note: forced to do GENERIC-* (cost 30)
;       unable to do inline fixnum arithmetic (cost 2) because:
;       The result is a (VALUES (MOD 21267647932558653929567424817066410001)
;                               &OPTIONAL), not a (VALUES FIXNUM &REST T).
;       unable to do inline (signed-byte 64) arithmetic (cost 4) because:
;       The result is a (VALUES (MOD 21267647932558653929567424817066410001)
;                               &OPTIONAL), not a (VALUES (SIGNED-BYTE 64) &REST
;                                                         T).
;       etc.

; file: /imojudge/sandbox/Main.lisp
; in: DEFUN MAKE-CSC-FROM-ARRAY
;     (AREF ARRAY CP/CSC::ROW CP/CSC::COL)
; --> LET* 
; ==>
;   (SB-KERNEL:HAIRY-DATA-VECTOR-REF ARRAY SB-INT:INDEX)
; 
; note: unable to
;   avoid runtime dispatch on array element type
; due to type uncertainty:
;   The first argument is a (ARRAY * (* *)), not a SIMPLE-ARRAY.

;     (ZEROP CP/CSC::VALUE)
; ==>
;   (= CP/CSC::VALUE 0)
; 
; note: unable to
;   open-code FLOAT to RATIONAL comparison
; due to type uncertainty:
;   The first argument is a NUMBER, not a FLOAT.
; 
; note: unable to
;   open-code FLOAT to RATIONAL comparison
; due to type uncertainty:
;   The first argument is a NUMBER, not a (OR (COMPLEX SINGLE-FLOAT)
;                                             (COMPLEX DOUBLE-FLOAT)).
; 
; note: unab...

ジャッジ結果

セット名 Subtask1 Subtask2 All
得点 / 配点 30 / 30 30 / 30 0 / 140
結果
AC × 37
AC × 36
AC × 79
TLE × 28
セット名 テストケース
Subtask1 00_00_sample.txt, 00_01_sample.txt, 00_02_sample.txt, 00_03_random.txt, 00_04_random.txt, 00_05_random.txt, 00_06_random.txt, 00_07_random.txt, 00_08_random.txt, 00_09_random.txt, 00_10_random.txt, 00_11_random.txt, 00_12_random.txt, 00_13_random.txt, 00_14_random.txt, 00_15_random.txt, 00_16_random.txt, 00_17_random.txt, 00_18_random.txt, 00_19_random.txt, 00_20_random.txt, 00_21_random.txt, 00_22_random.txt, 00_23_freedom.txt, 00_24_freedom.txt, 00_25_freedom.txt, 00_26_full.txt, 00_27_full.txt, 00_28_full.txt, 00_29_min.txt, 00_30_min.txt, 00_31_min.txt, 00_32_max.txt, 00_33_max.txt, 00_34_max.txt, 00_35_max.txt, 00_36_max.txt
Subtask2 01_37_sample.txt, 01_38_sample.txt, 01_39_random.txt, 01_40_random.txt, 01_41_random.txt, 01_42_random.txt, 01_43_random.txt, 01_44_random.txt, 01_45_random.txt, 01_46_random.txt, 01_47_random.txt, 01_48_random.txt, 01_49_random.txt, 01_50_random.txt, 01_51_random.txt, 01_52_random.txt, 01_53_random.txt, 01_54_random.txt, 01_55_random.txt, 01_56_random.txt, 01_57_random.txt, 01_58_random.txt, 01_59_freedom.txt, 01_60_freedom.txt, 01_61_freedom.txt, 01_62_full.txt, 01_63_full.txt, 01_64_full.txt, 01_65_min.txt, 01_66_min.txt, 01_67_min.txt, 01_68_max.txt, 01_69_max.txt, 01_70_max.txt, 01_71_max.txt, 01_72_max.txt
All 00_00_sample.txt, 00_01_sample.txt, 00_02_sample.txt, 00_03_random.txt, 00_04_random.txt, 00_05_random.txt, 00_06_random.txt, 00_07_random.txt, 00_08_random.txt, 00_09_random.txt, 00_10_random.txt, 00_11_random.txt, 00_12_random.txt, 00_13_random.txt, 00_14_random.txt, 00_15_random.txt, 00_16_random.txt, 00_17_random.txt, 00_18_random.txt, 00_19_random.txt, 00_20_random.txt, 00_21_random.txt, 00_22_random.txt, 00_23_freedom.txt, 00_24_freedom.txt, 00_25_freedom.txt, 00_26_full.txt, 00_27_full.txt, 00_28_full.txt, 00_29_min.txt, 00_30_min.txt, 00_31_min.txt, 00_32_max.txt, 00_33_max.txt, 00_34_max.txt, 00_35_max.txt, 00_36_max.txt, 01_37_sample.txt, 01_38_sample.txt, 01_39_random.txt, 01_40_random.txt, 01_41_random.txt, 01_42_random.txt, 01_43_random.txt, 01_44_random.txt, 01_45_random.txt, 01_46_random.txt, 01_47_random.txt, 01_48_random.txt, 01_49_random.txt, 01_50_random.txt, 01_51_random.txt, 01_52_random.txt, 01_53_random.txt, 01_54_random.txt, 01_55_random.txt, 01_56_random.txt, 01_57_random.txt, 01_58_random.txt, 01_59_freedom.txt, 01_60_freedom.txt, 01_61_freedom.txt, 01_62_full.txt, 01_63_full.txt, 01_64_full.txt, 01_65_min.txt, 01_66_min.txt, 01_67_min.txt, 01_68_max.txt, 01_69_max.txt, 01_70_max.txt, 01_71_max.txt, 01_72_max.txt, 02_100_min.txt, 02_101_min.txt, 02_102_max.txt, 02_103_max.txt, 02_104_max.txt, 02_105_max.txt, 02_106_max.txt, 02_73_random.txt, 02_74_random.txt, 02_75_random.txt, 02_76_random.txt, 02_77_random.txt, 02_78_random.txt, 02_79_random.txt, 02_80_random.txt, 02_81_random.txt, 02_82_random.txt, 02_83_random.txt, 02_84_random.txt, 02_85_random.txt, 02_86_random.txt, 02_87_random.txt, 02_88_random.txt, 02_89_random.txt, 02_90_random.txt, 02_91_random.txt, 02_92_random.txt, 02_93_freedom.txt, 02_94_freedom.txt, 02_95_freedom.txt, 02_96_full.txt, 02_97_full.txt, 02_98_full.txt, 02_99_min.txt
ケース名 結果 実行時間 メモリ
00_00_sample.txt AC 27 ms 28172 KiB
00_01_sample.txt AC 24 ms 28228 KiB
00_02_sample.txt AC 26 ms 28452 KiB
00_03_random.txt AC 18 ms 28324 KiB
00_04_random.txt AC 21 ms 29044 KiB
00_05_random.txt AC 22 ms 28712 KiB
00_06_random.txt AC 25 ms 28488 KiB
00_07_random.txt AC 27 ms 28212 KiB
00_08_random.txt AC 23 ms 28396 KiB
00_09_random.txt AC 20 ms 28460 KiB
00_10_random.txt AC 20 ms 28544 KiB
00_11_random.txt AC 19 ms 28376 KiB
00_12_random.txt AC 23 ms 30740 KiB
00_13_random.txt AC 20 ms 28168 KiB
00_14_random.txt AC 22 ms 28972 KiB
00_15_random.txt AC 19 ms 28236 KiB
00_16_random.txt AC 27 ms 28432 KiB
00_17_random.txt AC 20 ms 28368 KiB
00_18_random.txt AC 20 ms 28572 KiB
00_19_random.txt AC 21 ms 29300 KiB
00_20_random.txt AC 20 ms 28424 KiB
00_21_random.txt AC 20 ms 28812 KiB
00_22_random.txt AC 19 ms 28312 KiB
00_23_freedom.txt AC 25 ms 28484 KiB
00_24_freedom.txt AC 20 ms 28416 KiB
00_25_freedom.txt AC 18 ms 28648 KiB
00_26_full.txt AC 19 ms 28776 KiB
00_27_full.txt AC 24 ms 29776 KiB
00_28_full.txt AC 28 ms 29152 KiB
00_29_min.txt AC 20 ms 28240 KiB
00_30_min.txt AC 18 ms 28184 KiB
00_31_min.txt AC 18 ms 28188 KiB
00_32_max.txt AC 26 ms 28612 KiB
00_33_max.txt AC 28 ms 31584 KiB
00_34_max.txt AC 19 ms 28588 KiB
00_35_max.txt AC 26 ms 29868 KiB
00_36_max.txt AC 27 ms 29864 KiB
01_37_sample.txt AC 21 ms 28224 KiB
01_38_sample.txt AC 18 ms 28240 KiB
01_39_random.txt AC 272 ms 89160 KiB
01_40_random.txt AC 688 ms 96828 KiB
01_41_random.txt AC 54 ms 41712 KiB
01_42_random.txt AC 38 ms 34796 KiB
01_43_random.txt AC 19 ms 28140 KiB
01_44_random.txt AC 235 ms 90048 KiB
01_45_random.txt AC 34 ms 31992 KiB
01_46_random.txt AC 91 ms 58964 KiB
01_47_random.txt AC 26 ms 28588 KiB
01_48_random.txt AC 34 ms 34288 KiB
01_49_random.txt AC 103 ms 64760 KiB
01_50_random.txt AC 71 ms 48784 KiB
01_51_random.txt AC 19 ms 29184 KiB
01_52_random.txt AC 107 ms 65808 KiB
01_53_random.txt AC 65 ms 48028 KiB
01_54_random.txt AC 38 ms 34456 KiB
01_55_random.txt AC 86 ms 56148 KiB
01_56_random.txt AC 152 ms 83956 KiB
01_57_random.txt AC 113 ms 68696 KiB
01_58_random.txt AC 118 ms 71876 KiB
01_59_freedom.txt AC 29 ms 29684 KiB
01_60_freedom.txt AC 32 ms 31080 KiB
01_61_freedom.txt AC 22 ms 31112 KiB
01_62_full.txt AC 197 ms 81424 KiB
01_63_full.txt AC 320 ms 89200 KiB
01_64_full.txt AC 197 ms 82060 KiB
01_65_min.txt AC 18 ms 28236 KiB
01_66_min.txt AC 17 ms 28248 KiB
01_67_min.txt AC 20 ms 28184 KiB
01_68_max.txt AC 87 ms 56444 KiB
01_69_max.txt AC 100 ms 61516 KiB
01_70_max.txt AC 83 ms 54704 KiB
01_71_max.txt AC 60 ms 45608 KiB
01_72_max.txt AC 206 ms 88136 KiB
02_100_min.txt AC 26 ms 28164 KiB
02_101_min.txt AC 17 ms 28188 KiB
02_102_max.txt TLE 2218 ms 464428 KiB
02_103_max.txt TLE 2217 ms 462636 KiB
02_104_max.txt TLE 2213 ms 435500 KiB
02_105_max.txt TLE 2218 ms 470100 KiB
02_106_max.txt TLE 2217 ms 466108 KiB
02_73_random.txt TLE 2216 ms 415820 KiB
02_74_random.txt TLE 2217 ms 464076 KiB
02_75_random.txt TLE 2212 ms 271900 KiB
02_76_random.txt TLE 2213 ms 464716 KiB
02_77_random.txt TLE 2210 ms 302216 KiB
02_78_random.txt TLE 2214 ms 353756 KiB
02_79_random.txt TLE 2210 ms 201872 KiB
02_80_random.txt TLE 2212 ms 446280 KiB
02_81_random.txt TLE 2212 ms 449056 KiB
02_82_random.txt TLE 2214 ms 374396 KiB
02_83_random.txt TLE 2213 ms 278024 KiB
02_84_random.txt TLE 2213 ms 347460 KiB
02_85_random.txt TLE 2213 ms 436228 KiB
02_86_random.txt TLE 2214 ms 346228 KiB
02_87_random.txt TLE 2210 ms 207640 KiB
02_88_random.txt TLE 2212 ms 465748 KiB
02_89_random.txt TLE 2215 ms 518712 KiB
02_90_random.txt TLE 2210 ms 237908 KiB
02_91_random.txt TLE 2209 ms 150804 KiB
02_92_random.txt TLE 2212 ms 311488 KiB
02_93_freedom.txt AC 439 ms 226408 KiB
02_94_freedom.txt AC 235 ms 127612 KiB
02_95_freedom.txt AC 334 ms 175620 KiB
02_96_full.txt TLE 2208 ms 139356 KiB
02_97_full.txt TLE 2216 ms 472816 KiB
02_98_full.txt TLE 2212 ms 478604 KiB
02_99_min.txt AC 28 ms 28200 KiB