<commit_before>(ns ^{:author "<NAME>"}
  uncomplicate.neanderthal.core
  "Contains type-agnostic linear algebraic functions. Typically,
  you would want to require this namespace regardless of the actual type
  (real, complex, CPU, GPU, pure Java etc.) of the vectors and matrices that
  you use.

  In cases when you need to repeatedly call a function from this namespace
  that accesses individual entries, and the entries are primitive, it
  is better to use a primitive version of the function from
  uncomplicate.neanderthal.core namespace.
  Additionally, constructor functions for different kinds of vectors
  (native, GPU, pure java) are in respective specialized namespaces.

  You need to take care to only use vectors and matrices
  of the same type in the same function call. These functions do not support
  arguments of mixed types. For example, you can not call the
  dot function with one double vector (dv) and one float vector (fv),
  or for one vector in the CPU memory and one in the GPU memory.

  ## Examples

  (ns test
    (:require [uncomplicate.neanderthal core native]))

  (ns test
    (:require [uncomplicate.neanderthal core native opencl]))
  "
  (:require  [uncomplicate.neanderthal
              [protocols :as p]
              [math :refer [f= pow sqrt]]])
  (:import [uncomplicate.neanderthal.protocols Vector Matrix Block
            BLAS BLASPlus Changeable RealChangeable DataAccessor]))

;; ================== Category functions  ==============

(defn fmap!
  ([f x]
   (p/fmap! x f))
  ([f x y]
   (p/fmap! x f y))
  ([f x y z]
   (p/fmap! x f y z))
  ([f x y z w]
   (p/fmap! x f y z w))
  ([f x y z w & ws]
   (apply p/fmap! x f y z w ws)))

(defn fold
  ([x] ;;TODO all categorical functions than can be primitive should be checked
   (p/fold x))
  ([f x]
   (p/fold x f))
  ([f id x]
   (p/fold x f id)))

(defn freduce
  ([f x]
   (p/freduce x f))
  ([f acc x]
   (p/freduce x acc f))
  ([f acc x y]
   (p/freduce x acc f y))
  ([f acc x y z]
   (p/freduce x acc f y z))
  ([f acc x y z & ws]
   (apply p/freduce x acc f y z ws)))

(defn vect?
  "Returns true if x implements uncomplicate.neanderthal.protocols.Vector.

  (vect? (dv 1 2 3)) => true
  (vect? [1 2 3]) => false
  "
  [x]
  (instance? Vector x))

(defn matrix?
  "Returns true if x implements uncomplicate.neanderthal.protocols.Matrix.

  (matrix? (dge 3 2 [1 2 3 4 5 6])) => true
  (matrix? [[1 2] [3 4] [5 6]]) => false
  "
  [x]
  (instance? Matrix x))

(defmulti transfer!
  "Transfers the data from source in one type of memory, to the appropriate
  destination in another type of memory. Typically you would use it when you want to
  move data between the host memory and the OpenCL device memory. If you want to
  simply move data from one container to another in the same memory space,
  you should use copy.  If you call transfer in one memory space, it would simply
  be copied.

  (transfer! (sv 1 2 3) device-vect)
  (transfer! device-vect (sv 3))
  "
  (fn [source destination] [(class source) (class destination)]))

(defn create
  "Creates an initialized vector of the dimension n, or a  matrix m x n,
  using the provided factory.
  More specific methods are available in technology-specific namespaces.

  See uncomplicate.neanderthal.native, uncomplicate.neanderthal.opencl, etc.

  (create cblas-single 3)
  (create cblas-double 35 12)"
  ([factory ^long n]
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (p/create-vector factory n
                      (.initialize acc (.createDataSource acc n))
                      nil)))
  ([factory ^long m ^long n]
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (p/create-matrix factory m n
                      (.initialize acc (.createDataSource acc (* m n)))
                      nil))))

(defn create-raw
  "Creates an uninitialized vector of the dimension n, or a  matrix m x n,
  using the provided factory. It might or might not be initialized to zeroes,
  depending of the underlying memory (DirectBytebuffer is zero-initialized,
  OpenCL CLBuffer contains random junk). If you need to be sure that the
  new object is filled with zeros, consider using the create function.

  More specific methods are available in technology-specific namespaces.

  See uncomplicate.neanderthal.native, uncomplicate.neanderthal.opencl, etc.

  (create-init cblas-single 3)
  (create-init cblas-double 35 12)"
  ([factory ^long n]
   (p/create-vector factory n
                    (.createDataSource (p/data-accessor factory) n)
                    nil))
  ([factory ^long m ^long n]
   (p/create-matrix factory m n
                    (.createDataSource (p/data-accessor factory) (* m n))
                    nil)))

(defn create-vector
  ([factory source];;TODO documentation
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (cond
       (integer? source) (create factory source)
       (sequential? source) (transfer! source (create-raw factory (count source)))
       (vect? source) (transfer! source (create-raw factory (.dim ^Vector source)))
       (float? source) (.set ^RealChangeable (create-raw factory 1) 0 source)
       source (p/create-vector factory
                               (.count ^DataAccessor (p/data-accessor factory)
                                       source)
                               source nil)
       :default (throw (IllegalArgumentException.
                        (format p/ILLEGAL_SOURCE_MSG (type source) "vectors"))))))
  ([factory x & xs]
   (create-vector factory (cons x xs))))

(defn create-ge-matrix
  ([factory m n source]
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (cond
       (sequential? source) (transfer! source (create-raw factory m n))
       (matrix? source)
       (transfer! source (create-raw factory
                                     (.mrows ^Matrix source)
                                     (.ncols ^Matrix source)))
       source (p/create-matrix factory m n source p/DEFAULT_ORDER)
       :default (throw (IllegalArgumentException.
                        (format p/ILLEGAL_SOURCE_MSG (type source)
                                "general matrices"))))))
  ([factory m n]<commit_msg>Added documentation for a few newly added functions in core.<commit_after>(ns ^{:author "<NAME>"}
  uncomplicate.neanderthal.core
  "Contains type-agnostic linear algebraic functions. Typically,
  you would want to require this namespace regardless of the actual type
  (real, complex, CPU, GPU, pure Java etc.) of the vectors and matrices that
  you use.

  In cases when you need to repeatedly call a function from this namespace
  that accesses individual entries, and the entries are primitive, it
  is better to use a primitive version of the function from
  uncomplicate.neanderthal.core namespace.
  Additionally, constructor functions for different kinds of vectors
  (native, GPU, pure java) are in respective specialized namespaces.

  You need to take care to only use vectors and matrices
  of the same type in the same function call. These functions do not support
  arguments of mixed types. For example, you can not call the
  dot function with one double vector (dv) and one float vector (fv),
  or for one vector in the CPU memory and one in the GPU memory.

  ## Examples

  (ns test
    (:require [uncomplicate.neanderthal core native]))

  (ns test
    (:require [uncomplicate.neanderthal core native opencl]))
  "
  (:require  [uncomplicate.neanderthal
              [protocols :as p]
              [math :refer [f= pow sqrt]]])
  (:import [uncomplicate.neanderthal.protocols Vector Matrix Block
            BLAS BLASPlus Changeable RealChangeable DataAccessor]))

;; ================== Category functions  ==============

(defn fmap!
  ([f x]
   (p/fmap! x f))
  ([f x y]
   (p/fmap! x f y))
  ([f x y z]
   (p/fmap! x f y z))
  ([f x y z w]
   (p/fmap! x f y z w))
  ([f x y z w & ws]
   (apply p/fmap! x f y z w ws)))

(defn fold
  ([x] ;;TODO all categorical functions than can be primitive should be checked
   (p/fold x))
  ([f x]
   (p/fold x f))
  ([f id x]
   (p/fold x f id)))

(defn freduce
  ([f x]
   (p/freduce x f))
  ([f acc x]
   (p/freduce x acc f))
  ([f acc x y]
   (p/freduce x acc f y))
  ([f acc x y z]
   (p/freduce x acc f y z))
  ([f acc x y z & ws]
   (apply p/freduce x acc f y z ws)))

(defn vect?
  "Returns true if x implements uncomplicate.neanderthal.protocols.Vector.

  (vect? (dv 1 2 3)) => true
  (vect? [1 2 3]) => false
  "
  [x]
  (instance? Vector x))

(defn matrix?
  "Returns true if x implements uncomplicate.neanderthal.protocols.Matrix.

  (matrix? (dge 3 2 [1 2 3 4 5 6])) => true
  (matrix? [[1 2] [3 4] [5 6]]) => false
  "
  [x]
  (instance? Matrix x))

(defmulti transfer!
  "Transfers the data from source in one type of memory, to the appropriate
  destination in another type of memory. Typically you would use it when you want to
  move data between the host memory and the OpenCL device memory. If you want to
  simply move data from one container to another in the same memory space,
  you should use copy.  If you call transfer in one memory space, it would simply
  be copied.

  (transfer! (sv 1 2 3) device-vect)
  (transfer! device-vect (sv 3))
  "
  (fn [source destination] [(class source) (class destination)]))

(defn create
  "Creates an initialized vector of the dimension n, or a  matrix m x n,
  using the provided factory.
  More specific methods are available in technology-specific namespaces.

  See uncomplicate.neanderthal.native, uncomplicate.neanderthal.opencl, etc.

  (create cblas-single 3)
  (create cblas-double 35 12)"
  ([factory ^long n]
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (p/create-vector factory n
                      (.initialize acc (.createDataSource acc n))
                      nil)))
  ([factory ^long m ^long n]
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (p/create-matrix factory m n
                      (.initialize acc (.createDataSource acc (* m n)))
                      nil))))

(defn create-raw
  "Creates an uninitialized vector of the dimension n, or a  matrix m x n,
  using the provided factory. It might or might not be initialized to zeroes,
  depending of the underlying memory (DirectBytebuffer is zero-initialized,
  OpenCL CLBuffer contains random junk). If you need to be sure that the
  new object is filled with zeros, consider using the create function.

  More specific methods are available in technology-specific namespaces.

  See uncomplicate.neanderthal.native, uncomplicate.neanderthal.opencl, etc.

  (create-raw cblas-single 3)
  (create-raw cblas-double 35 12)"
  ([factory ^long n]
   (p/create-vector factory n
                    (.createDataSource (p/data-accessor factory) n)
                    nil))
  ([factory ^long m ^long n]
   (p/create-matrix factory m n
                    (.createDataSource (p/data-accessor factory) (* m n))
                    nil)))

(defn create-vector
  "Creates a vector from source using the provided factory.

  Accepts the following source:
  - java.nio.ByteBuffer with a capacity divisible by the element width,
  . which will be used as-is for backing the vector.
  - a positive integer, which will be used as a dimension
  . of new vector with zeroes as entries.
  - a floating point number, which will be the only entry
  . in a one-dimensional vector.
  - a clojure sequence, which will be copied into a
  . direct ByteBuffer that backs the new vector.
  - varargs will be treated as a clojure sequence.

  (create-vector *double-factory* [1 2 3])
  (create-vector *single-factory* 12)
  "
  ([factory source]
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (cond
       (integer? source) (create factory source)
       (sequential? source) (transfer! source (create-raw factory (count source)))
       (vect? source) (transfer! source (create-raw factory (.dim ^Vector source)))
       (float? source) (.set ^RealChangeable (create-raw factory 1) 0 source)
       source (p/create-vector factory
                               (.count ^DataAccessor (p/data-accessor factory)
                                       source)
                               source nil)
       :default (throw (IllegalArgumentException.
                        (format p/ILLEGAL_SOURCE_MSG (type source) "vectors"))))))
  ([factory x & xs]
   (create-vector factory (cons x xs))))

(defn create-ge-matrix
  "Creates a dense, column-oriented mxn matrix from source.

  If called with two arguments, creates a zero matrix with dimensions mxn.

  Accepts the following sources:
  - java.nio.ByteBuffer with a capacity = elementWidth * m * n,
  . which will be used as-is for backing the matrix.
  - a clojure sequence, which will be copied into a
  . direct ByteBuffer that backs the new vector.

  (create-ge-matrix *double-factory* 15 13)
  "
  ([factory m n source]
   (let [acc ^DataAccessor (p/data-accessor factory)]
     (cond
       (sequential? source) (transfer! source (create-raw factory m n))
       (matrix? source)
       (transfer! source (create-raw factory
                                     (.mrows ^Matrix source)
                                     (.ncols ^Matrix source)))
       source (p/create-matrix factory m n source p/DEFAULT_ORDER)
       :default (throw (IllegalArgumentException.
                        (format p/ILLEGAL_SOURCE_MSG (type source)
                                "general matrices"))))))
  ([factory m n]
{'fraction_non_alphanumeric': 0.09855072463768116, 'fraction_numerical': 0.006020066889632107, 'mean_word_length': 2.635774115104026, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6951460', 'n_tokens_mistral': 4127, 'n_tokens_neox': 3893, 'n_words': 1681}