0 | {--
   1 | Copyright (C) 2021  Joel Berkeley
   2 |
   3 | This program is free software: you can redistribute it and/or modify
   4 | it under the terms of the GNU Affero General Public License as published
   5 | by the Free Software Foundation, either version 3 of the License, or
   6 | (at your option) any later version.
   7 |
   8 | This program is distributed in the hope that it will be useful,
   9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 | GNU Affero General Public License for more details.
  12 |
  13 | You should have received a copy of the GNU Affero General Public License
  14 | along with this program.  If not, see <https://www.gnu.org/licenses/>.
  15 | --}
  16 | ||| Defines `Tensor`, an array of numbers or booleans, along with a number of functions operating on
  17 | ||| `Tensor`s. `Tensor` operations typically leverage hardware acceleration and graph compilation.
  18 | ||| spidr tracks tensor shape and data type in the types, so you can be sure that if your tensor
  19 | ||| code compiles, these are consistent.
  20 | |||
  21 | ||| spidr achieves efficient reuse of tensor computations with `Tag`. See the tutorial
  22 | ||| _Nuisances in the Tensor API_ for a discussion of pitfalls to avoid when using `Tag`.
  23 | module Spidr.Tensor
  24 |
  25 | import public Control.Monad.State
  26 | import Control.Monad.Error.Either
  27 | import Data.Singleton
  28 | import Syntax.PreorderReasoning
  29 |
  30 | import Spidr.Compiler.Eval
  31 | import Spidr.Compiler.IR
  32 | import Spidr.Compiler.Array
  33 | import Spidr.Compiler.LiteralRW
  34 | import Spidr.Compiler.Passes
  35 | import Spidr.Device
  36 | import public Spidr.DType
  37 | import public Spidr.Data.Literal
  38 | import public Spidr.Shape
  39 | import public Spidr.Data.List
  40 | import Spidr.Data.Vect
  41 |
  42 | ||| A scalar or array. Construct a `Tensor` with function `tensor`.
  43 | export
  44 | data Tensor : Shape -> DType -> Type where
  45 |   MkTensor : Value -> {shape : _} -> {dtype : _} -> Tensor shape dtype
  46 |
  47 | (.type) : Tensor shape dtype -> ValueType
  48 | (.type) (MkTensor {shape, dtype} _) = TensorType shape dtype
  49 |
  50 | (.value) : Tensor s t -> Value
  51 | (.value) (MkTensor v) = v
  52 |
  53 | ||| The effect of tagging nodes in a computational graph.
  54 | export
  55 | data TagT : (Type -> Type) -> Type -> Type where
  56 |   MkTagT : StateT Env m a -> TagT m a
  57 |
  58 | public export 0
  59 | Tag : Type -> Type
  60 | Tag = TagT Identity
  61 |
  62 | export
  63 | Functor m => Functor (TagT m) where
  64 |   map f (MkTagT x) = MkTagT (map f x)
  65 |
  66 | export
  67 | Monad m => Applicative (TagT m) where
  68 |   pure x = MkTagT (pure x)
  69 |   (MkTagT f) <*> (MkTagT x) = MkTagT (f <*> x)
  70 |
  71 | export
  72 | Monad m => Monad (TagT m) where
  73 |   (MkTagT x) >>= f = MkTagT $ x >>= (\y => let MkTagT z = f y in z)
  74 |
  75 | export
  76 | MonadTrans TagT where
  77 |   lift = MkTagT . lift
  78 |
  79 | public export
  80 | interface Taggable a where
  81 |   ||| Mark an expression to be efficiently reused. For example, in
  82 |   ||| ```
  83 |   ||| bad : Tensor [9999999] F64
  84 |   ||| bad = let x = fill {shape = [9999999]} 1.0 in x + x
  85 |   |||
  86 |   ||| good : Tag $ Tensor [9999999] F64
  87 |   ||| good = do x <- tag $ fill {shape = [9999999]} 1.0
  88 |   |||           pure (x + x)
  89 |   ||| ```
  90 |   ||| the large vector `x` is calculated twice in `bad`, but once in `good`, as `tag` marks it for
  91 |   ||| sharing.
  92 |   |||
  93 |   ||| Types that implement this interface should `tag` constituent components it deems worth sharing.
  94 |   ||| For example, see the implementation for tuples.
  95 |   |||
  96 |   ||| See tutorial _Nuisances in the Tensor API_ for details.
  97 |   tag : Monad m => a -> TagT m a
  98 |
  99 | Taggable OpRef where
 100 |   tag = MkTagT . tagOpRef
 101 |
 102 | export
 103 | Taggable (Tensor shape dtype) where
 104 |   tag (MkTensor $ V idx op) = map (\op => MkTensor $ V idx op) (tag op)
 105 |
 106 | export
 107 | (Taggable a, Taggable b) => Taggable (a, b) where
 108 |   tag (a, b) = Prelude.[| (tag a, tag b) |]
 109 |
 110 | val0 : Op -> Value
 111 | val0 = V 0 . Concrete
 112 |
 113 | t0 : {shape : _} -> {dtype : _} -> Op -> Tensor shape dtype
 114 | t0 x = MkTensor $ val0 x
 115 |
 116 | ||| Construct a `Tensor` from `Literal` data. For example
 117 | ||| ```
 118 | ||| x : Tensor [2, 3] S32
 119 | ||| x = tensor [[1, 2, 3],
 120 | |||             [4, 5, 6]]
 121 | ||| ```
 122 | export
 123 | tensor : {shape : _} -> {dtype : _} -> Literal shape (idrisType dtype) -> Tensor shape dtype
 124 | tensor lit = t0 $ Lit shape dtype lit
 125 |
 126 | namespace F64
 127 |   export
 128 |   fromDouble : Double -> Tensor [] F64
 129 |   fromDouble = tensor . Scalar
 130 |
 131 | try : Show e => EitherT e IO a -> IO a
 132 | try = eitherT (\e => assert_total $ idris_crash $ show e) pure
 133 |
 134 | %hide Literal.All2.All2
 135 |
 136 | namespace List
 137 |   namespace Tag
 138 |     ||| Evaluate a list of `Tensor`s as a list of `Literal`s. Tensors in the list can have different
 139 |     ||| shapes and element types. For example,
 140 |     ||| ```
 141 |     ||| main : Device -> IO ()
 142 |     ||| main device = do [x, y] <- eval device $ do let x = tensor {dtype = F64} [1.2, 3.4]
 143 |     |||                                             y <- reduce @{Sum} [0] x
 144 |     |||                                             pure [x, y]
 145 |     |||                  printLn x
 146 |     |||                  printLn y
 147 |     ||| ```
 148 |     ||| In contrast to `Tensor.eval` when called on multiple tensors, this function constructs and
 149 |     ||| compiles the graph just once.
 150 |     export covering
 151 |     eval :
 152 |       forall shapes, dtypes .
 153 |       Device ->
 154 |       Tag (All2 Tensor shapes dtypes) ->
 155 |       IO (All2 Literal shapes (DType.idrisType <$> dtypes))
 156 |     eval device (MkTagT xs) =
 157 |       let (env, xs) = runState empty xs
 158 |           main = MkFn 0 [] (extract (.type) xs) (extract (.value) xs) env
 159 |           types = mapProperty (\(MkTensor _) => MkTensorData ()) xs
 160 |        in try $ readAll <$> execute device main types
 161 |
 162 |       where
 163 |
 164 |       extract : (forall s, t . Tensor s t -> a) -> All2 Tensor ss tt -> Vect (length ss) a
 165 |       extract f [] = []
 166 |       extract f (x :: xs) = f x :: extract f xs
 167 |
 168 |       readAll :
 169 |         All2 (TensorData $ \_ => Array . DType.idrisType) s t ->
 170 |         All2 Literal s (DType.idrisType <$> t)
 171 |       readAll [] = []
 172 |       readAll (MkTensorData {dtype} l :: ls) = read dtype l :: readAll ls
 173 |
 174 |   ||| A convenience wrapper for `List.Tag.eval`, for use with a bare list of `Tensor`s.
 175 |   export covering
 176 |   eval :
 177 |     forall shapes, dtypes .
 178 |     Device ->
 179 |     All2 Tensor shapes dtypes ->
 180 |     IO (All2 Literal shapes (DType.idrisType <$> dtypes))
 181 |   eval device xs = eval device (pure xs)
 182 |
 183 | namespace Tag
 184 |   ||| Evaluate a `Tensor`, returning its value as a `Literal`. This function builds and executes the
 185 |   ||| computational graph.
 186 |   |||
 187 |   ||| **Note:** Each call to `eval` will rebuild and execute the graph; multiple calls to `eval` on
 188 |   ||| different tensors, even if they are in the same computation, will be treated independently.
 189 |   ||| To efficiently evaluate multiple tensors at once, use `List.Tag.eval`.
 190 |   export covering
 191 |   eval : Device -> Tag (Tensor shape dtype) -> IO (Literal shape (DType.idrisType dtype))
 192 |   eval device x = map (\[z] => z) $ List.Tag.eval device $ map (\z => [z]) x
 193 |
 194 | ||| A convenience wrapper for `Tag.eval`, for use with a bare `Tensor`.
 195 | export covering
 196 | eval : Device -> Tensor shape dtype -> IO (Literal shape (DType.idrisType dtype))
 197 | eval device x = eval device (pure x)
 198 |
 199 | ||| A string representation of a tensor graph.
 200 | |||
 201 | ||| There are no guarantees whatsoever as to the string structure and contents.
 202 | export covering
 203 | Show (Tag $ Tensor shape dtype) where
 204 |   show (MkTagT x) =
 205 |     let (env, MkTensor x) = runState empty x
 206 |      in show (MkFn 0 [] [TensorType shape dtype] [x] env)
 207 |
 208 | export covering
 209 | Show (Tensor shape dtype) where show = show . pure {f = Tag}
 210 |
 211 | ||| Positive infinity.
 212 | export
 213 | inf : Tensor [] F64
 214 |
 215 | ||| NaN (not a number).
 216 | export
 217 | nan : Tensor [] F64
 218 |
 219 | namespace Bound
 220 |   ||| Compares less than or equal to any other value (except NaN).
 221 |   export
 222 |   min : Ord dtype => Tensor [] dtype
 223 |   min @{OrdS8}  = t0 $ MinValue S8
 224 |   min @{OrdS16} = t0 $ MinValue S16
 225 |   min @{OrdS32} = t0 $ MinValue S32
 226 |   min @{OrdS64} = t0 $ MinValue S64
 227 |   min @{OrdU8}  = t0 $ MinValue U8
 228 |   min @{OrdU16} = t0 $ MinValue U16
 229 |   min @{OrdU32} = t0 $ MinValue U32
 230 |   min @{OrdU64} = t0 $ MinValue U64
 231 |   min @{OrdF64} = tensor $ Scalar $ -1.0 / 0.0
 232 |
 233 |   ||| Compares greater than or equal to any other value (except NaN).
 234 |   export
 235 |   max : Ord dtype => Tensor [] dtype
 236 |   max @{OrdS8}  = t0 $ MaxValue S8
 237 |   max @{OrdS16} = t0 $ MaxValue S16
 238 |   max @{OrdS32} = t0 $ MaxValue S32
 239 |   max @{OrdS64} = t0 $ MaxValue S64
 240 |   max @{OrdU8}  = t0 $ MaxValue U8
 241 |   max @{OrdU16} = t0 $ MaxValue U16
 242 |   max @{OrdU32} = t0 $ MaxValue U32
 243 |   max @{OrdU64} = t0 $ MaxValue U64
 244 |   max @{OrdF64} = tensor $ Scalar $ 1.0 / 0.0
 245 |
 246 | ||| The most negative possible finite float, approx. -1.8e308
 247 | export
 248 | minFinite : Tensor [] F64
 249 | minFinite = t0 MinFiniteFloat
 250 |
 251 | ||| The most positive possible finite float, approx. 1.8e308
 252 | export
 253 | maxFinite : Tensor [] F64
 254 | maxFinite = t0 MaxFiniteFloat
 255 |
 256 | ||| Cast the element type. For example, `castDtype (tensor {dtype = S32} [1, -2])` is
 257 | ||| `tensor {dtype = F64} [1.0, -2.0]`.
 258 | export
 259 | castDtype : Integral dtype => Tensor shape dtype -> Tensor shape F64
 260 | castDtype $ MkTensor {shape} x = t0 $ Convert F64 shape x
 261 |
 262 | ||| A function type. For example `Func [Nat, String] Bool` is `Nat -> String -> Bool`.
 263 | public export 0
 264 | Func : Vect arity Type -> Type -> Type
 265 | Func [] r = r
 266 | Func (t :: ts) r = t -> Func ts r
 267 |
 268 | mapFunc : (a -> b) -> {arity : Nat} -> {0 xs : Vect arity Type} -> Func xs a -> Func xs b
 269 | mapFunc f {arity = 0} {xs = []} g = f g
 270 | mapFunc f {arity = (S k)} {xs = _ :: _} g = \x => mapFunc f (g x)
 271 |
 272 | mkFn' :
 273 |   forall arity, rshapes, rdtypes . (shapes : Vect arity Shape) -> (dtypes : Vect arity DType) ->
 274 |   Func [| Tensor shapes dtypes |] (Tag $ All2 Tensor rshapes rdtypes) ->
 275 |   Tag (Fn arity, All2 Tensor rshapes rdtypes)
 276 | mkFn' shapes dtypes f = MkTagT $ do
 277 |   addr <- reserve
 278 |
 279 |   let leq : length shapes === arity
 280 |       leq = lengthCorrect shapes
 281 |
 282 |   let MkTagT res = applyNary addr (length shapes) _ _ $ rewrite leq in f
 283 |       (env, results) = runState (emptyFrom !get) res
 284 |       resAndTys = fromList $ resultsAndTypes results
 285 |       argValueTypes = zipWith TensorType shapes dtypes
 286 |       f : Fn arity = MkFn addr argValueTypes (snd <$> resAndTys) (fst <$> resAndTys) env
 287 |
 288 |   updateCounterFrom env
 289 |
 290 |   pure (f, results)
 291 |
 292 |   where
 293 |
 294 |   applyNary :
 295 |     (addr, ar : Nat) ->
 296 |     (ss : Vect ar Shape) ->
 297 |     (ds : Vect ar DType) ->
 298 |     Func [| Tensor ss ds |] a -> a
 299 |   applyNary addr 0 [] [] f = f
 300 |   applyNary addr (S a) (s :: ss) (t :: ts) f =
 301 |     applyNary addr a ss ts (f $ MkTensor $ V (length shapes `minus` S a) $ BoundSet addr)
 302 |
 303 |   resultsAndTypes : All2 Tensor s d -> List (Value, ValueType)
 304 |   resultsAndTypes [] = []
 305 |   resultsAndTypes ((MkTensor {shape, dtype} x) :: xs) =
 306 |     (x, TensorType shape dtype) :: resultsAndTypes xs
 307 |
 308 | mkFn :
 309 |   {arity : _} -> (shapes : Vect arity Shape) -> (dtypes : Vect arity DType) ->
 310 |   forall rshapes, rdtypes .
 311 |   Func [| Tensor shapes dtypes |] (Tag $ All2 Tensor rshapes rdtypes) -> Tag $ Fn arity
 312 | mkFn shapes dtypes f = fst <$> mkFn' shapes dtypes f
 313 |
 314 | mkFn1 :
 315 |   {arity : _} -> (shapes : Vect arity Shape) -> (dtypes : Vect arity DType) ->
 316 |   Func [| Tensor shapes dtypes |] (Tag $ Tensor rshape rdtype) -> Tag $ Fn arity
 317 | mkFn1 shapes dtypes f =
 318 |   mkFn shapes dtypes $ mapFunc (\x => pure $ the (All2 _ _ _) [!x]) f
 319 |
 320 | covering
 321 | namedFunc :
 322 |   {arity : _} -> {shapes : Vect arity Shape} -> {dtypes : Vect arity DType} ->
 323 |   forall rshapes, rdtypes .
 324 |   (shapeFn : Shape -> Shape) ->
 325 |   (forall extra . Fn (arity + extra) -> Vect arity Value -> Vect extra Value -> Op) ->
 326 |   Func [| Tensor shapes dtypes |] (Tag $ All2 Tensor rshapes rdtypes) ->
 327 |   Tag $ Func [| Tensor (shapeFn <$> shapes) dtypes |] $
 328 |     Tag $ All2 Tensor (shapeFn <$> rshapes) rdtypes
 329 | namedFunc shapeFn remapResults f = do
 330 |   (f, results) <- mkFn' shapes dtypes {rshapes, rdtypes} f
 331 |   let (extraArgs, f) = snd $ removeCaptures {n = arity} f
 332 |   MkTagT $ modify {ops $= ((f.tag, NamedFunc f) ::)}
 333 |   let remap = \args =>
 334 |         retarget 0 results <$> tag (Concrete $ remapResults f args extraArgs)
 335 |   pure $ mapFunc remap $ args [] arity (shapeFn <$> shapes) dtypes
 336 |
 337 |   where
 338 |
 339 |   args :
 340 |     (acc : Vect p Value) ->
 341 |     (0 ar : Nat) ->
 342 |     (ss : Vect ar Shape) ->
 343 |     (ds : Vect ar DType) ->
 344 |     Func [| Tensor ss ds |] $ Vect (p + ar) Value
 345 |   args acc 0 [] [] = rewrite plusZeroRightNeutral p in acc
 346 |   args acc (S a) (s :: ss) (t :: ts) = \(MkTensor x) =>
 347 |     rewrite sym $ plusSuccRightSucc p a in args (snoc acc x) a ss ts
 348 |
 349 |   retarget : Nat -> All2 Tensor ss ds -> OpRef -> All2 Tensor (shapeFn <$> ss) ds
 350 |   retarget k [] x = []
 351 |   retarget k (MkTensor {shape, dtype} _ :: xs) x =
 352 |     MkTensor {shape = shapeFn shape, dtype} (V k x) :: retarget (S k) xs x
 353 |
 354 | ||| Function abstraction in the framework IR.
 355 | |||
 356 | ||| Operations in spidr are, by default, inlined, which can lead to large IRs. `func` abstracts
 357 | ||| (and names) a function in the IR. The resulting function will have the exact same semantics as
 358 | ||| the input, though may perform differently, depending on ML compiler behaviour.
 359 | |||
 360 | ||| Implementation note: MLIR (more specifically the "func" dialect) only supports named functions
 361 | ||| at the top (or module) level. To achieve this, `func` lifts its function to the top level,
 362 | ||| and automatically converts any variable capture to new function arguments. As such, the IR
 363 | ||| may appear different to the Idris code from which it derives.
 364 | export covering
 365 | func :
 366 |   {shapes : Vect arity Shape} -> {dtypes : Vect arity DType} -> forall rshapes, rdtypes .
 367 |   let fn = Func [| Tensor shapes dtypes |] $ Tag $ All2 Tensor rshapes rdtypes in fn -> Tag fn
 368 | func f =
 369 |   rewrite sym $ functorIdentity shapes in
 370 |   rewrite sym $ functorIdentity rshapes in
 371 |   let lc = lengthCorrect (map id shapes) in
 372 |   rewrite sym lc in
 373 |     namedFunc {arity = length (map id shapes)} id (rewrite lc in remapResults) (rewrite lc in f)
 374 |
 375 |   where
 376 |   remapResults : Fn (arity + extra) -> Vect arity Value -> Vect extra Value -> Op
 377 |   remapResults f explicitArgs extraArgs =
 378 |     CallByName f.tag (toList $ f.resultTypes) (toList $ explicitArgs ++ extraArgs)
 379 |
 380 | ||| (Experimental) function vectorization.
 381 | |||
 382 | ||| Lift a function on tensors, so that it applies element-wise across the common leading dimension
 383 | ||| of its tensor arguments. For example, for
 384 | ||| ```
 385 | ||| xs : Tensor [2, 3, 3] S32
 386 | ||| xs = tensor [[[ 0,  1,  2],
 387 | |||               [ 3,  4,  5],
 388 | |||               [ 6,  7,  8]],
 389 | |||              [[ 9, 10, 11],
 390 | |||               [12, 13, 14],
 391 | |||               [15, 16, 17]]]
 392 | |||
 393 | ||| ys : Tensor [2] S32
 394 | ||| ys = Tensor [2, -1]
 395 | ||| ```
 396 | ||| `do !(vmap (\x, y => pure $ y * diag x)) xs ys` produces `tensor [[0, 8, 16], [-9, -13, -17]]`.
 397 | |||
 398 | ||| **Warning:** `vmap` is experimental, and only implemented for a subset of the tensor API. You
 399 | ||| can see approximately which operations are supported on the Enzyme [tracking issue](https://github.com/EnzymeAD/Enzyme-JAX/issues/152).
 400 | export partial
 401 | vmap :
 402 |   {n : _} ->
 403 |   {shapes : Vect arity Shape} -> {dtypes : Vect arity DType} ->
 404 |   {rshapes : _} -> {rdtypes : _} ->
 405 |   Func [| Tensor shapes dtypes |] (Tag $ All2 Tensor rshapes rdtypes) ->
 406 |   Tag $ Func [| Tensor (map (n ::) shapes) dtypes |]
 407 |     (Tag $ All2 Tensor (map (n ::) rshapes) rdtypes)
 408 | vmap f =
 409 |   let lc = lengthCorrect shapes in
 410 |   rewrite sym lc in
 411 |     namedFunc {arity = length shapes} (n ::) (rewrite lc in remapResults) (rewrite lc in f)
 412 |
 413 |   where
 414 |   remapResults : Fn (arity + extra) -> Vect arity Value -> Vect extra Value -> Op
 415 |   remapResults f explicitArgs extraArgs =
 416 |     let extraArgs = map (V 0 . Concrete . Broadcast (AddLeading [n])) extraArgs
 417 |         outTys = zipWith (TensorType . (n ::)) rshapes rdtypes
 418 |      in Vectorize outTys [n] f.tag (toList $ explicitArgs ++ extraArgs)
 419 |
 420 | ||| (Experimental) reverse-mode automatic differentiation.
 421 | |||
 422 | ||| `grad` can be applied repeatedly to obtain higher derivatives, though we do not yet support
 423 | ||| derivatives of vector-valued functions.
 424 | |||
 425 | ||| For example, for
 426 | ||| ```
 427 | ||| f : Tensor [2] F64 -> Tag $ Tensor [] F64
 428 | ||| f x = do
 429 | |||   x <- tag x
 430 | |||   let (x0, x1) = (slice [at 0] x, slice [at 1] x)
 431 | |||   pure $ x0 / x1
 432 | ||| ```
 433 | ||| `grad f (tensor [3.0, 2.0])` produces `tensor [0.5, -0.75]`.
 434 | |||
 435 | ||| **Warning:** `grad` is experimental, and only implemented for a subset of the tensor API. You
 436 | ||| can see approximately which operations are supported on the Enzyme [tracking issue](https://github.com/EnzymeAD/Enzyme-JAX/issues/88).
 437 | export partial
 438 | grad : (Tensor shape F64 -> Tag $ Tensor [] F64) -> Tensor shape F64 -> Tag $ Tensor shape F64
 439 | grad f (MkTensor x) = pure $ t0 $ Grad shape !(mkFn1 [shape] [_] f) x
 440 |
 441 | %hide Prelude.Interfaces.product
 442 |
 443 | public export
 444 | product : List Nat -> Nat
 445 | product [] = 1
 446 | product (x :: xs) = x * product xs
 447 |
 448 | public export
 449 | sum : List Nat -> Nat
 450 | sum [] = 0
 451 | sum (x :: xs) = x + sum xs
 452 |
 453 | export
 454 | flattenable : (xs : List Nat) -> product xs === product [product xs]
 455 | flattenable [] = Refl
 456 | flattenable (x :: xs) = rewrite multOneRightNeutral (x * product xs) in Refl
 457 |
 458 | ||| Reshape a `Tensor`. For example, `reshape {to = [2, 1]} (tensor [3, 4])` is
 459 | ||| `tensor [[3], [4]]`. The output can have a different rank to the input.
 460 | export
 461 | reshape :
 462 |   {to : _} ->
 463 |   {auto 0 sizesEqual : product from = product to} ->
 464 |   Tensor from dtype ->
 465 |   Tensor to dtype
 466 | reshape $ MkTensor {shape} x = t0 $ Reshape dtype to x
 467 |
 468 | ||| Add a dimension of length one at the specified `axis`. The new dimension will be at the
 469 | ||| specified `axis` in the new `Tensor` (as opposed to the original `Tensor`). For example,
 470 | ||| `expand 1 $ tensor [[1, 2], [3, 4], [5, 6]]` is `tensor [[[1, 2]], [[3, 4]], [[5, 6]]]`.
 471 | export
 472 | expand :
 473 |   (axis : Nat) ->
 474 |   {auto 0 inBounds : axis `LTE` length shape} ->
 475 |   Tensor shape dtype ->
 476 |   Tensor (insertAt axis 1 shape) dtype
 477 | expand axis $ MkTensor {shape = _} x = t0 $ Reshape dtype (insertAt axis 1 shape) x
 478 |
 479 | namespace Squeezable
 480 |   ||| A `Squeezable from to` constitutes proof that the shape `from` can be squeezed to the
 481 |   ||| shape `to`. Squeezing is the process of removing any number of dimensions of length one.
 482 |   public export
 483 |   data Squeezable : (0 from : Shape) -> (0 to : Shape) -> Type where
 484 |     ||| Proof that a shape can be squeezed to itself. For example:
 485 |     |||
 486 |     ||| [] to []
 487 |     ||| [3, 4] to [3, 4]
 488 |     Same : Squeezable x x
 489 |
 490 |     ||| Proof that any dimensions (including those of length 1) can be preserved in the process of
 491 |     ||| squeezing. For example:
 492 |     |||
 493 |     ||| ...
 494 |     Match : Squeezable from to -> Squeezable (x :: from) (x :: to)
 495 |
 496 |     ||| Proof that any dimensions of length one can be squeezed out. For example:
 497 |     |||
 498 |     ||| [1, 3, 1, 1, 4] to [3, 4]
 499 |     Nest : Squeezable from to -> Squeezable (1 :: from) to
 500 |
 501 | ||| Remove dimensions of length one from a `Tensor` such that it has the desired shape. For example:
 502 | |||
 503 | ||| ```
 504 | ||| x : Tensor [2, 1, 3, 1] S32
 505 | ||| x = tensor [[[[4], [5], [6]]],
 506 | |||             [[[7], [8], [9]]]]
 507 | |||
 508 | ||| y : Tensor [2, 1, 3] S32
 509 | ||| y = squeeze x
 510 | ||| ```
 511 | ||| is
 512 | ||| ```
 513 | ||| y : Tensor [2, 1, 3] S32
 514 | ||| y = tensor [[[4, 5, 6]],
 515 | |||             [[7, 8, 9]]]
 516 | ||| ```
 517 | export
 518 | squeeze :
 519 |   {to : _} ->
 520 |   {auto 0 shapesSqueezable : Squeezable from to} ->
 521 |   Tensor from dtype ->
 522 |   Tensor to dtype
 523 | squeeze $ MkTensor {shape} x = t0 $ Reshape dtype to x
 524 |
 525 | ||| A `SliceOrIndex d` is a valid slice or index into a dimension of size `d`. See `slice` for
 526 | ||| details.
 527 | export
 528 | data SliceOrIndex : Nat -> Type where
 529 |   Slice :
 530 |     (from, to : Nat) ->
 531 |     {size : _} ->
 532 |     {auto 0 fromTo : from + size = to} ->
 533 |     {auto 0 inDim : LTE to d} ->
 534 |     SliceOrIndex d
 535 |   Index : (idx : Nat) -> {auto 0 inDim : LT idx d} -> SliceOrIndex d
 536 |   DynamicSlice : Tensor [] U64 -> (size : Nat) -> {auto 0 inDim : LTE size d} -> SliceOrIndex d
 537 |   DynamicIndex : Tensor [] U64 -> SliceOrIndex d
 538 |
 539 | ||| Index at `idx`. See `slice` for details.
 540 | public export
 541 | at : (idx : Nat) -> {auto 0 inDim : LT idx d} -> SliceOrIndex d
 542 | at = Index
 543 |
 544 | namespace Dynamic
 545 |   ||| Index at the specified index. See `slice` for details.
 546 |   public export
 547 |   at : Tensor [] U64 -> SliceOrIndex d
 548 |   at = DynamicIndex
 549 |
 550 | ||| Slice from `from` (inclusive) to `to` (exclusive). See `slice` for details.
 551 | public export
 552 | (.to) :
 553 |   (from, to : Nat) ->
 554 |   {size : _} ->
 555 |   {auto 0 fromTo : from + size = to} ->
 556 |   {auto 0 inDim : LTE to d} ->
 557 |   SliceOrIndex d
 558 | (.to) = Slice
 559 |
 560 | ||| Slice `size` elements starting at the specified scalar `U64` index. See `slice` for details.
 561 | public export
 562 | (.size) : Tensor [] U64 -> (size : Nat) -> {auto 0 inDim : LTE size d} -> SliceOrIndex d
 563 | (.size) = DynamicSlice
 564 |
 565 | ||| Slice across all indices along an axis. See `slice` for details.
 566 | public export
 567 | all : {d : _} -> SliceOrIndex d
 568 | all = Slice 0 @{%search} @{reflexive {ty = Nat}} d
 569 |
 570 | ||| A `MultiSlice shape` is a valid multi-dimensional slice into a tensor with shape `shape`.
 571 | ||| See `slice` for details.
 572 | public export
 573 | data MultiSlice : Shape -> Type where
 574 |   Nil : MultiSlice ds
 575 |   (::) : SliceOrIndex d -> MultiSlice ds -> MultiSlice (d :: ds)
 576 |
 577 | namespace MultiSlice
 578 |   ||| The shape of a tensor produced by slicing with the specified multi-dimensional slice. See
 579 |   ||| `Tensor.slice` for details.
 580 |   public export
 581 |   slice : {shape : _} -> MultiSlice shape -> Shape
 582 |   slice {shape} [] = shape
 583 |   slice {shape = (_ :: _)} (Slice {size} _ _ :: xs) = size :: slice xs
 584 |   slice {shape = (_ :: _)} (Index _ :: xs) = slice xs
 585 |   slice {shape = (_ :: _)} (DynamicSlice _ size :: xs) = size :: slice xs
 586 |   slice {shape = (_ :: _)} (DynamicIndex _ :: xs) = slice xs
 587 |
 588 | ||| Slice or index `Tensor` axes. Each axis can be sliced or indexed, and this can be done with
 589 | ||| either static (`Nat`) or dynamic (scalar `U64`) indices.
 590 | |||
 591 | ||| **Static indices**
 592 | |||
 593 | ||| Static indices are `Nat`s. For example, for
 594 | ||| ```
 595 | ||| x : Tensor [5, 6] S32
 596 | ||| x = tensor [[ 0,  1,  2,  3,  4,  5],
 597 | |||             [ 6,  7,  8,  9, 10, 11],
 598 | |||             [12, 13, 14, 15, 16, 17],
 599 | |||             [18, 19, 20, 21, 22, 23],
 600 | |||             [24, 25, 26, 27, 28, 29]]
 601 | ||| ```
 602 | ||| we can index as `slice [at 1] x` to get
 603 | ||| ```
 604 | ||| x : Tensor [6] S32
 605 | ||| x = tensor [6, 7, 8, 9, 10, 11]
 606 | ||| ```
 607 | ||| or we can slice as `slice [2.to 4] x` to get
 608 | ||| ```
 609 | ||| x : Tensor [2, 6] S32
 610 | ||| x = tensor [[12, 13, 14, 15, 16, 17],
 611 | |||             [18, 19, 20, 21, 22, 23]]
 612 | ||| ```
 613 | ||| Note that in `2.to 4`, the 2 is inclusive, and the 4 exclusive, so we return indices 2 and 3.
 614 | |||
 615 | ||| **Dynamic indices**
 616 | |||
 617 | ||| Dynamic indices are scalar `U64` values, and the API works slightly differently because we
 618 | ||| can't know the value of dynamic indices until the graph is executed. For indexing, with scalar
 619 | ||| `U64` index `i` in `slice [at i] x`, `i` is clamped to be a valid index into that dimension.
 620 | ||| For example, for `i = tensor 1`, `slice [at i] x` is
 621 | ||| ```
 622 | ||| x : Tensor [6] S32
 623 | ||| x = tensor [6, 7, 8, 9, 10, 11]
 624 | ||| ```
 625 | ||| as in the static case. However, for `i = tensor 10`, `slice [at i] x` returns the last row
 626 | ||| ```
 627 | ||| x : Tensor [6] S32
 628 | ||| x = tensor [24, 25, 26, 27, 28, 29]
 629 | ||| ```
 630 | ||| We can also slice by specifying a scalar `U64` start index, and a static size, as
 631 | ||| `slice [i.size 2] x` with `i = tensor 2` to get
 632 | ||| ```
 633 | ||| x : Tensor [2, 6] S32
 634 | ||| x = tensor [[12, 13, 14, 15, 16, 17],
 635 | |||             [18, 19, 20, 21, 22, 23]]
 636 | ||| ```
 637 | ||| For a given slice `size`, the dynamic start index is clamped such that we always get `size`
 638 | ||| elements along that axis. For example, `slice [i.size 2] x` with `i = tensor 4` is
 639 | ||| ```
 640 | ||| x : Tensor [2, 6] S32
 641 | ||| x = tensor [[18, 19, 20, 21, 22, 23],
 642 | |||             [24, 25, 26, 27, 28, 29]]
 643 | ||| ```
 644 | ||| which starts at index 3 rather than index 4.
 645 | |||
 646 | ||| **Mixed static, dynamic, slicing and indexing**
 647 | |||
 648 | ||| Each axis can only be sliced or indexed, and must use only static or dynamic indices. However,
 649 | ||| across axes, we can mix these four arbitrarily. For example, with `slice [2.to 4, at 1] x` to
 650 | ||| get
 651 | ||| ```
 652 | ||| x : Tensor [2] S32
 653 | ||| x = tensor [13, 19]
 654 | ||| ```
 655 | ||| or with `i = tensor 2` in `slice [at 1, i.size 2] x` to get
 656 | ||| ```
 657 | ||| x : Tensor [2] S32
 658 | ||| x = tensor [7, 8]
 659 | ||| ```
 660 | |||
 661 | ||| Slices and indices apply to the leading axes of the tensor. For trailing axes omitted from the
 662 | ||| multi-dimensional slice, the whole of the axis is returned. If we want to slice or index over
 663 | ||| later axes and retain all indices in a leading axis, we can use the convenience function `all`,
 664 | ||| as `slice [all, at 3] x` to get
 665 | ||| ```
 666 | ||| x : Tensor [5] S32
 667 | ||| x = tensor [[3], [9], [15], [21], [27]]
 668 | ||| ```
 669 | ||| This is exactly the same as the more manual `slice [0.to 5, at 3] x` and
 670 | ||| `slice [(tensor 0).size 5, at 3] x`.
 671 | |||
 672 | ||| @at The multi-dimensional slices and indices at which to slice the tensor.
 673 | export
 674 | slice : (at : MultiSlice shape) -> Tensor shape dtype -> Tensor (slice at) dtype
 675 | slice at $ MkTensor x = MkTensor $
 676 |   let x = val0 $ Slice (mapd start (const 0) at) (mapd stop id at) (replicate (length shape) 1) x
 677 |       -- we shortcut DynamicSlice to allow autodiff for static slicing
 678 |       x = if isDynamic at then val0 $ DynamicSlice (dynStarts [] at) (mapd size id at) x else x
 679 |    in val0 $ Reshape dtype (MultiSlice.slice at) x
 680 |
 681 |       where
 682 |       mapd : ((Nat -> a) -> {d : Nat} -> SliceOrIndex d -> a) ->
 683 |              (Nat -> a) ->
 684 |              {shape : Shape} ->
 685 |              MultiSlice shape ->
 686 |              List a
 687 |       mapd _ dflt {shape} [] = map dflt shape
 688 |       mapd f dflt (x :: xs) = f dflt x :: mapd f dflt xs
 689 |
 690 |       start : (Nat -> Nat) -> {d : Nat} -> SliceOrIndex d -> Nat
 691 |       start _ (Slice from _) = from
 692 |       start _ (Index idx) = idx
 693 |       start f {d} _ = f d
 694 |
 695 |       stop : (Nat -> Nat) -> {d : Nat} -> SliceOrIndex d -> Nat
 696 |       stop _ (Slice _ to) = to
 697 |       stop _ (Index idx) = S idx
 698 |       stop f {d} _ = f d
 699 |
 700 |       size : (Nat -> Nat) -> {d : Nat} -> SliceOrIndex d -> Nat
 701 |       size _ (Slice {size = size'} _ _) = size'
 702 |       size _ (Index _) = 1
 703 |       size _ (DynamicSlice _ size') = size'
 704 |       size _ (DynamicIndex _) = 1
 705 |
 706 |       zero : Value
 707 |       zero = val0 $ Lit [] U64 $ Scalar 0
 708 |
 709 |       isDynamic : {shape : _} -> MultiSlice shape -> Bool
 710 |       isDynamic [] = False
 711 |       isDynamic {shape = (_ :: _)} (DynamicSlice _ _ :: _) = True
 712 |       isDynamic {shape = (_ :: _)} (DynamicIndex _ :: _) = True
 713 |       isDynamic (_ :: ds) = isDynamic ds
 714 |
 715 |       dynStarts : List Value -> {shape : _} -> MultiSlice shape -> List Value
 716 |       dynStarts idxs {shape} [] = replicate (length shape) zero ++ idxs
 717 |       dynStarts idxs (DynamicSlice (MkTensor i) _ :: ds) = i :: dynStarts idxs ds
 718 |       dynStarts idxs (DynamicIndex (MkTensor i) :: ds) = i :: dynStarts idxs ds
 719 |       dynStarts idxs (_ :: ds) = zero :: dynStarts idxs ds
 720 |
 721 | ||| The starting indices of a slice with shape `sizes`, into a tensor with shape `bounds`.
 722 | export
 723 | data MultiIndex : (sizes, bounds : Shape) -> Type where
 724 |   INil : MultiIndex [] []
 725 |   IConsStatic :
 726 |     (idx : Nat) ->
 727 |     {auto inBounds : LTE (idx + s) b} ->
 728 |     MultiIndex ss bs ->
 729 |     MultiIndex (s :: ss) (b :: bs)
 730 |   IConsDynamic :
 731 |     Tensor [] U64 ->
 732 |     {auto inBounds : LTE s b} ->
 733 |     MultiIndex ss bs ->
 734 |     MultiIndex (s :: ss) (b :: bs)
 735 |
 736 | namespace MultiIndex
 737 |   ||| Scalar.
 738 |   public export
 739 |   Nil : MultiIndex [] []
 740 |   Nil = INil
 741 |
 742 |   namespace Static
 743 |     ||| A `Nat` starting index. This is statically restricted to be in bounds.
 744 |     public export
 745 |     (::) :
 746 |       (idx : Nat) ->
 747 |       {auto inBounds : LTE (idx + s) b} ->
 748 |       MultiIndex ss bs ->
 749 |       MultiIndex (s :: ss) (b :: bs)
 750 |     (::) = IConsStatic
 751 |
 752 |   namespace Dynamic
 753 |     ||| A scalar `U64` starting index. This is dynamically truncated to be in bounds.
 754 |     public export
 755 |     (::) :
 756 |       Tensor [] U64 ->
 757 |       {auto inBounds : LTE s b} ->
 758 |       MultiIndex ss bs ->
 759 |       MultiIndex (s :: ss) (b :: bs)
 760 |     (::) = IConsDynamic
 761 |
 762 | ||| Replace a slice of a tensor. For example, for
 763 | ||| ```
 764 | ||| target : Tensor [3, 4] S32
 765 | ||| target = tensor [[ 0,  1,  2,  3],
 766 | |||                  [ 4,  5,  6,  7],
 767 | |||                  [ 8,  9, 10, 11]]
 768 | |||
 769 | ||| update : Tensor [2, 2] S32
 770 | ||| update = tensor [[12, 13],
 771 | |||                  [14, 15]]
 772 | ||| ```
 773 | ||| `updateSlice [0, 1] update target` is
 774 | ||| ```
 775 | ||| y : Tensor [3, 4] S32
 776 | ||| y = tensor [[ 0, 12, 13,  3],
 777 | |||             [ 4, 14, 15,  7],
 778 | |||             [ 8,  9, 10, 11]]
 779 | ||| ```
 780 | ||| The starting index can be specified along each axis using either a `Nat` or a `U64` scalar.
 781 | ||| Note that the updated slice will always be replaced by `update`, and lie fully within `target`.
 782 | ||| This is checked statically for `Nat`. However, for `U64` scalar, the start index `at` is
 783 | ||| truncated to the maximum index for which the slice remains within `target`. For example,
 784 | ||| `updateSlice [0, (tensor $ Scalar 2)] update target` and
 785 | ||| `updateSlice [0, (tensor $ Scalar 3)] update target`
 786 | ||| ```
 787 | ||| are both
 788 | ||| ```
 789 | ||| y : Tensor [3, 4] S32
 790 | ||| y = tensor [[ 0,  1, 12, 13],
 791 | |||             [ 4,  5, 14, 15],
 792 | |||             [ 8,  9, 10, 11]]
 793 | ||| ```
 794 | |||
 795 | ||| @at The starting indices of the slice to replace.
 796 | ||| @update The tensor to replace the slice with.
 797 | ||| @target The tensor in which to replace the slice.
 798 | export
 799 | updateSlice :
 800 |   (at : MultiIndex updateShape shape) ->
 801 |   (update : Tensor updateShape dtype) ->
 802 |   (target : Tensor shape dtype) ->
 803 |   Tensor shape dtype
 804 | updateSlice at (MkTensor update) (MkTensor target) =
 805 |   t0 $ DynamicUpdateSlice target update (toList at)
 806 |
 807 |   where
 808 |
 809 |   toList : MultiIndex s r -> List Value
 810 |   toList INil = []
 811 |   toList (IConsStatic idx idxs) = val0 (Lit [] U64 (Scalar $ cast idx)) :: toList idxs
 812 |   toList (IConsDynamic (MkTensor idx) idxs) = idx :: toList idxs
 813 |
 814 | unappend : (xs : List a) -> Singleton (xs ++ ys) -> Singleton ys
 815 | unappend xs vxys with 0 (xs ++ ys) proof p
 816 |   unappend [] (Val xys) | xys = rewrite p in Val xys
 817 |   unappend (_ :: xs) (Val (_ :: xys)) | (_ :: xys) =
 818 |     unappend xs (rewrite snd $ biinjective p in Val xys)
 819 |
 820 | head : {0 xs : List a} -> Singleton (x :: xs) -> Singleton x
 821 | head (Val (x :: xs)) = Val x
 822 |
 823 | tail : {0 xs : List a} -> Singleton (x :: xs) -> Singleton xs
 824 | tail (Val (x :: xs)) = Val xs
 825 |
 826 | gather : {0 xs : List a} -> All Singleton xs -> Singleton xs
 827 | gather [] = Val []
 828 | gather (Val x :: xs) = let Val xs = gather xs in Val (x :: xs)
 829 |
 830 | map : (f : a -> b) -> Singleton x -> Singleton (f x)
 831 | map f (Val x) = Val (f x)
 832 |
 833 | shapeOnly : Tensor shape dtype -> Singleton shape
 834 | shapeOnly (MkTensor _) = Val shape
 835 |
 836 | ||| Concatenate tensors along a common axis. For example,
 837 | ||| `concat {leading = []} [tensor [[1, 2]], tensor [[3, 4]], tensor [[5, 6]]]` and
 838 | ||| `concat {leading = [_]} [tensor [[1], [3], [5]], tensor [[2], [4], [6]]]` are both
 839 | ||| `tensor [[1, 2], [3, 4], [5, 6]]`.
 840 | export
 841 | concat :
 842 |   {leading : _} ->
 843 |   All (\n => Tensor (leading ++ n :: tail) dtype) (n :: ns) ->
 844 |   Tensor (leading ++ sum (n :: ns) :: tail) dtype
 845 | -- much of this function is a workaround for https://github.com/idris-lang/Idris2/issues/3860
 846 | concat (x@(MkTensor {shape = shape@(.(_))} _) :: xs) =
 847 |   let nns = gather $ mapProperty (\s => head $ unappend leading $ shapeOnly s) (x :: xs)
 848 |       tail' = Tensor.tail $ unappend leading (shapeOnly x)
 849 |       Val shape@(_) : Singleton _ = map (leading ++) [| map Tensor.sum nns :: tail' |]
 850 |    in t0 {shape} $ Concat (length leading) (x.value :: fromList (forget $ mapProperty (.value) xs))
 851 |
 852 | ||| Transpose a matrix. For example, `(tensor [[1, 2], [3, 4]]).T` is `tensor [[1, 3], [2, 4]]`.
 853 | export
 854 | (.T) : Tensor [m, n] dtype -> Tensor [n, m] dtype
 855 | (MkTensor x).T = t0 $ Transpose [1, 0] x
 856 |
 857 | ||| Transpose axes of a tensor. This is a more general version of `(.T)`, in which you can
 858 | ||| transpose any number of axes in a tensor of arbitrary rank. The i'th axis in the resulting
 859 | ||| tensor corresponds to the `index i ordering`'th axis in the input tensor. For example, for
 860 | ||| ```
 861 | ||| x : Tensor [2, 3, 4] S32
 862 | ||| x = tensor [[[ 0,  1,  2,  3],
 863 | |||              [ 4,  5,  6,  7],
 864 | |||              [ 8,  9, 10, 11]],
 865 | |||             [[12, 13, 14, 15],
 866 | |||              [16, 17, 18, 19],
 867 | |||              [20, 21, 22, 23]]]
 868 | ||| ```
 869 | ||| `transpose [0, 2, 1] x` is
 870 | ||| ```
 871 | ||| x : Tensor [2, 4, 3] S32
 872 | ||| x = tensor [[[ 0,  4,  8],
 873 | |||              [ 1,  5,  9],
 874 | |||              [ 2,  6, 10],
 875 | |||              [ 3,  7, 11]],
 876 | |||             [[12, 16, 20],
 877 | |||              [13, 17, 21],
 878 | |||              [14, 18, 22],
 879 | |||              [15, 19, 23]]]
 880 | ||| ```
 881 | ||| `transpose [2, 0, 1] x` is
 882 | ||| ```
 883 | ||| x : Tensor [4, 2, 3] S32
 884 | ||| x = tensor [[[ 0,  4,  8],
 885 | |||              [12, 16, 20]],
 886 | |||             [[ 1,  5,  9],
 887 | |||              [13, 17, 21]],
 888 | |||             [[ 2,  6, 10],
 889 | |||              [14, 18, 22]],
 890 | |||             [[ 3,  7, 11],
 891 | |||              [15, 19, 23]]]
 892 | ||| ```
 893 | |||
 894 | ||| In order to see what effect transposing a tensor has, it can help to bear in mind the following:
 895 | ||| * if an element can be found with `slice [at 3, at 4, at 5] x` in the original tensor,
 896 | |||   that same element can instead be found with `slice [at 5, at 3, at 4]` given a
 897 | |||   `transpose [2, 0, 1]`. That is, transposing axes re-orders indices when indexing.
 898 | ||| * with `transpose [2, 0, 1]`, traversing the first axis in the result is equivalent to
 899 | |||   traversing the last axis in the input. Similarly, traversing the last axis in the result is
 900 | |||   equivalent to traversing the second axis in the input.
 901 | export
 902 | transpose :
 903 |   (ordering : List Nat) ->
 904 |   Tensor shape dtype ->
 905 |   {auto 0 lengths : length ordering = length shape} ->
 906 |   {auto 0 axesUnique : unique ordering = True} ->
 907 |   {auto 0 inBounds : All (flip InBounds shape) ordering} ->
 908 |   Tensor (multiIndex ordering shape) dtype
 909 | transpose ordering $ MkTensor x = t0 $ Transpose ordering x
 910 |
 911 | ||| A `DimBroadcastable from to` proves that a dimension of size `from` can be broadcast to a
 912 | ||| dimension of size `to`.
 913 | public export
 914 | data DimBroadcastable : (0 from : Nat) -> (0 to : Nat) -> Type where
 915 |   ||| Proof that any dimension can be broadcast to itself. For example in shapes `[2, 3]` to
 916 |   ||| `[2, 3]`.
 917 |   Same : DimBroadcastable x x
 918 |
 919 |   ||| Proof that a dimension of length one can be broadcast to any size. For example in shapes
 920 |   ||| `[2, 1]` to `[2, 3]`
 921 |   Stack : DimBroadcastable 1 _
 922 |
 923 |   ||| Proof that any dimension can be broadcast to zero. For example in shapes `[2, 3]` to `[2, 0]`.
 924 |   Zero : DimBroadcastable _ 0
 925 |
 926 | namespace Broadcastable
 927 |   ||| A `Broadcastable from to` constitutes proof that the shape `from` can be broadcast to the
 928 |   ||| shape `to`.
 929 |   public export
 930 |   data Broadcastable : (0 from : Shape) -> (0 to : Shape) -> Type where
 931 |     ||| Proof that a shape can be broadcast to itself. For example:
 932 |     |||
 933 |     ||| [] to []
 934 |     ||| [3, 4] to [3, 4]
 935 |     |||
 936 |     ||| Implementation note: we could have used `Broadcast [] []`, which would have resulted in more
 937 |     ||| atomic constructors for `Broadcastable`, but the author guesses that this implementation helps
 938 |     ||| the type checker avoid applications of `Match`.
 939 |     Same : Broadcastable x x
 940 |
 941 |     ||| Proof that a dimension of size `f` can be broadcast to size `t` if these dimensions
 942 |     ||| are `DimBroadcastable f t`. For example:
 943 |     |||
 944 |     ||| [2, 3] to [2, 3]
 945 |     ||| [2, 1] to [2, 3]
 946 |     ||| [2, 1] to [2, 0]
 947 |     Match : forall from, to .
 948 |             {auto 0 ranksEq : length from = length to} ->
 949 |             {auto 0 dimBroadcastable : DimBroadcastable f t} ->
 950 |             Broadcastable from to ->
 951 |             Broadcastable (f :: from) (t :: to)
 952 |
 953 |     ||| Proof that broadcasting can add outer dimensions i.e. nesting. For example:
 954 |     |||
 955 |     ||| [3] to [1, 3]
 956 |     ||| [3] to [5, 3]
 957 |     Nest : Broadcastable f t -> Broadcastable f (_ :: t)
 958 |
 959 | ||| A shape can be extended with any number of leading dimensions.
 960 | |||
 961 | ||| @leading The leading dimensions.
 962 | export
 963 | broadcastableByLeading : (leading : List Nat) -> Broadcastable shape (leading ++ shape)
 964 | broadcastableByLeading [] = Same
 965 | broadcastableByLeading (l :: ls) = Nest (broadcastableByLeading ls)
 966 |
 967 | ||| A scalar can be broadcast to any shape.
 968 | %hint
 969 | export
 970 | scalarToAnyOk : (to : Shape) -> Broadcastable [] to
 971 | scalarToAnyOk to = rewrite sym $ appendNilRightNeutral to in broadcastableByLeading to
 972 |
 973 | ||| Broadcast a `Tensor` to a new compatible shape. For example,
 974 | ||| ```
 975 | ||| x : Tensor [2, 3] S32
 976 | ||| x = broadcast (tensor [4, 5, 6])
 977 | ||| ```
 978 | ||| is
 979 | ||| ```
 980 | ||| x : Tensor [2, 3] S32
 981 | ||| x = tensor [[4, 5, 6], [4, 5, 6]]
 982 | ||| ```
 983 | export
 984 | broadcast :
 985 |   {to : _} -> {dtype : _} ->
 986 |   {auto shapesOK : Broadcastable from to} ->
 987 |   Tensor from dtype ->
 988 |   Tensor to dtype
 989 | broadcast $ MkTensor {shape = _} x = t0 $ Broadcast (Explicit to) x
 990 |
 991 | ||| A `Tensor` where every element has the specified value. For example,
 992 | ||| ```
 993 | ||| fives : Tensor [2, 3] S32
 994 | ||| fives = fill 5
 995 | ||| ```
 996 | ||| is
 997 | ||| ```
 998 | ||| fives : Tensor [2, 3] S32
 999 | ||| fives = tensor [[5, 5, 5],
1000 | |||                 [5, 5, 5]]
1001 | ||| ```
1002 | export
1003 | fill : {shape : _} -> {dtype : _} -> idrisType dtype -> Tensor shape dtype
1004 | fill x = broadcast {shapesOK = scalarToAnyOk shape} (tensor (Scalar x))
1005 |
1006 | ||| A constant where values increment from zero along the specified `axis`. For example,
1007 | ||| ```
1008 | ||| x : Tensor [3, 5] S32
1009 | ||| x = iota 1
1010 | ||| ```
1011 | ||| is the same as
1012 | ||| ```
1013 | ||| x : Tensor [3, 5] S32
1014 | ||| x = tensor [[0, 1, 2, 3, 4],
1015 | |||             [0, 1, 2, 3, 4],
1016 | |||             [0, 1, 2, 3, 4]]
1017 | ||| ```
1018 | ||| and
1019 | ||| ```
1020 | ||| x : Tensor [3, 5] S32
1021 | ||| x = iota 0
1022 | ||| ```
1023 | ||| is the same as
1024 | ||| ```
1025 | ||| x : Tensor [3, 5] S32
1026 | ||| x = tensor [[0, 0, 0, 0, 0],
1027 | |||             [1, 1, 1, 1, 1],
1028 | |||             [2, 2, 2, 2, 2]]
1029 | ||| ```
1030 | export
1031 | iota :
1032 |   {shape : _} ->
1033 |   {dtype : _} ->
1034 |   {auto 0 _ : Num dtype} ->
1035 |   (axis : Nat) ->
1036 |   {auto 0 inBounds : InBounds axis shape} ->
1037 |   Tensor shape dtype
1038 | iota dimension = t0 $ Iota shape dtype dimension
1039 |
1040 | ||| A while-loop operating on a single tensor.
1041 | |||
1042 | ||| `while1` iteratively checks if the tensor satisfies `condition`, and if it does, updates it with
1043 | ||| `body`.
1044 | |||
1045 | ||| **Note:** The XLA plugins impose heuristic-based rules on variable capture in higher-order
1046 | ||| functions. We do not comprehensively understand these rules, but you *might* experience runtime
1047 | ||| errors if you capture variables in `condition` or `body`, especially variables other than
1048 | ||| constants, or variables that depend on parameters to enclosing (StableHLO) scopes.
1049 | |||
1050 | ||| @condition The guard condition for each iteration.
1051 | ||| @body The update step.
1052 | ||| @initial The initial tensor.
1053 | export covering
1054 | while1 :
1055 |   (condition : Tensor shape dtype -> Tag $ Tensor [] PRED) ->
1056 |   (body : Tensor shape dtype -> Tag $ Tensor shape dtype) ->
1057 |   (initial : Tensor shape dtype) ->
1058 |   Tag $ Tensor shape dtype
1059 | while1 condition body (MkTensor i0) =
1060 |   pure $ t0 $ While !(mkFn1 [_] [_] condition) !(mkFn1 [_] [_] body) [i0]
1061 |
1062 | ||| A while-loop operating on two tensors.
1063 | |||
1064 | ||| `while2` iteratively checks if the tensors together satisfy `condition`, and if so, updates them
1065 | ||| with `body`.
1066 | |||
1067 | ||| **Note:** The XLA plugins impose heuristic-based rules on variable capture in higher-order
1068 | ||| functions. We do not comprehensively understand these rules, but you *might* experience runtime
1069 | ||| errors if you capture variables in `condition` or `body`, especially variables other than
1070 | ||| constants, or variables that depend on parameters to enclosing (StableHLO) scopes.
1071 | |||
1072 | ||| @condition The guard condition for each iteration.
1073 | ||| @body The update step.
1074 | ||| @initial One initial tensor.
1075 | ||| @initial' The other initial tensor.
1076 | export covering
1077 | while2 :
1078 |   (condition : Tensor s a -> Tensor s' a' -> Tag $ Tensor [] PRED) ->
1079 |   (body : Tensor s a -> Tensor s' a' -> Tag $ All2 Tensor [s, s'] [a, a']) ->
1080 |   (initial : Tensor s a) -> (initial' : Tensor s' a') ->
1081 |   Tag $ All2 Tensor [s, s'] [a, a']
1082 | while2 condition body (MkTensor i) (MkTensor i') = do
1083 |   res <- tag $ Concrete $ While !(mkFn1 [_, _] [_, _] condition) !(mkFn [_, _] [_, _] body) [i, i']
1084 |   pure [MkTensor $ V 0 res, MkTensor $ V 1 res]
1085 |
1086 | ||| Reduce elements along one `axis` of a `Tensor` according to a specified `reducer` `Monoid`.
1087 | ||| For example, if `x = tensor [[0, 1, 2], [3, 4, 5]]`, then reduce @{Sum} 0 x` produces
1088 | ||| `tensor [3, 5, 7]`, and `reduce @{Sum} 1 x` produces `tensor [3, 12]`.
1089 | |||
1090 | ||| **Note:** `Semigroup` doesn't use `Tag`, which limits the functions that can be used in
1091 | ||| `reduce`. However, the most commonly used semigroups don't need `Tag`, including `Sum`,
1092 | ||| `Prod`, `Min` and `Max`, so for ergonomics, we have opted to use `Monoid` as is. We can
1093 | ||| provide an overloaded variant if requested.
1094 | |||
1095 | ||| **Note:** The monoid should not depend on values bound to outer scopes, else runtime errors may
1096 | ||| occur.
1097 | |||
1098 | ||| @reducer How to reduce elements along the given `axis`.
1099 | ||| @axis The axis along which to reduce elements.
1100 | export
1101 | reduce :
1102 |   (reducer : Monoid (Tensor [] dtype)) =>
1103 |   (axes : List Nat) ->
1104 |   {auto 0 axesUnique : Sorted LT axes} ->
1105 |   {auto 0 axesInBounds : All (flip InBounds shape) axes} ->
1106 |   Tensor shape dtype ->
1107 |   Tag $ Tensor (deleteAt axes shape) dtype
1108 | reduce axes $ MkTensor x = do
1109 |   let semigroup : Monoid a -> Semigroup a
1110 |       semigroup _ = %search
1111 |
1112 |   g <- mkFn1 [_, _] [_, _] (pure .: (<+>) @{semigroup reducer})
1113 |   let MkTensor neutral' = neutral @{reducer}
1114 |   pure $ t0 $ Reduce g [neutral'] axes [x]
1115 |
1116 | ||| Sort the elements of a `Tensor` along a specified `dimension` according to a scalar-wise
1117 | ||| ordering. For sorting function `f`, elements are sorted such that for consecutive sorted
1118 | ||| elements `a` and `b`, either `f a b` is true, or `f a b` *and* `f b a` are false.
1119 | |||
1120 | ||| **Note:** Sorting is not stable, meaning elements that compare equal according the ordering may
1121 | ||| be sorted in a different order to the order they appear in the input.
1122 | |||
1123 | ||| **Note:** `sort` is limited to use comparison function without `Tag`. However, since the most
1124 | ||| commonly-used functions, including (>), (<), (>=), and (<=), don't use `Tag`, we have opted to
1125 | ||| omit it for ergonomics. We can trivially provide an overloaded variant if requested.
1126 | |||
1127 | ||| **Note:** The comparison function should not depend on values bound to outer scopes, else
1128 | ||| runtime errors may occur.
1129 | |||
1130 | ||| For example, for `x = tensor [[1, 6, 4], [3, 2, 5]]`, `sort (<) 0 x` produces
1131 | ||| `tensor [[1, 2, 4], [3, 6, 5]]`, while `sort (<) 1 x` produces
1132 | ||| `tensor [[1, 4, 6], [2, 3, 5]]`.
1133 | export
1134 | sort :
1135 |   (Tensor [] dtype -> Tensor [] dtype -> Tensor [] PRED) ->
1136 |   (dimension : Nat) ->
1137 |   Tensor shape dtype ->
1138 |   {auto 0 dimInBounds : InBounds dimension shape} ->
1139 |   Tag $ Tensor shape dtype
1140 | sort comp dimension $ MkTensor x =
1141 |   pure $ t0 $ Sort !(mkFn1 [_, _] [_, _] $ pure .: comp) dimension False x
1142 |
1143 | ||| Reverse elements along the specified axes. For example, for
1144 | ||| ```
1145 | ||| x : Tensor [2, 3] S32
1146 | ||| x = tensor [[-2, -1,  0],
1147 | |||             [ 1,  2,  3]]
1148 | ||| ```
1149 | ||| `reverse [0] x` is
1150 | ||| ```
1151 | ||| x : Tensor [2, 3] S32
1152 | ||| x = tensor [[ 1,  2,  3],
1153 | |||             [-2, -1,  0]]
1154 | ||| ```
1155 | ||| `reverse [1] x` is
1156 | ||| ```
1157 | ||| x : Tensor [2, 3] S32
1158 | ||| x = tensor [[ 0, -1, -2],
1159 | |||             [ 3,  2,  1]]
1160 | ||| ```
1161 | ||| and `reverse [0, 1] x` is
1162 | ||| ```
1163 | ||| x : Tensor [2, 3] S32
1164 | ||| x = tensor [[ 3,  2,  1],
1165 | |||             [ 0, -1, -2]]
1166 | ||| ```
1167 | |||
1168 | ||| **Note:** This function requires `axes` is ordered simply so that elements are unique.
1169 | ||| The ordering itself is irrelevant to the implementation, but ensures uniqueness without using
1170 | ||| proofs of contradiction that can be difficult for Idris to construct.
1171 | export
1172 | reverse :
1173 |   (axes : List Nat) ->
1174 |   {auto 0 axesUnique : Sorted LT axes} ->
1175 |   {auto 0 axesInBounds : All (flip InBounds shape) axes} ->
1176 |   Tensor shape dtype ->
1177 |   Tensor shape dtype
1178 | reverse axes $ MkTensor x = t0 $ Reverse axes x
1179 |
1180 | ewUnary : UnaryOp -> Tensor s a -> Tensor s a
1181 | ewUnary op $ MkTensor x = t0 $ UnaryElementwise op x
1182 |
1183 | ewUnary' : {a' : _} -> UnaryOp -> Tensor s a -> Tensor s a'
1184 | ewUnary' op $ MkTensor x = t0 $ UnaryElementwise op x
1185 |
1186 | ewBinary : BinaryOp -> Tensor s a -> Tensor s a -> Tensor s a
1187 | ewBinary op (MkTensor x) (MkTensor x') = t0 $ BinaryElementwise op x x'
1188 |
1189 | ewBinary' : {out : _} -> BinaryOp -> Tensor s a -> Tensor s a -> Tensor s out
1190 | ewBinary' op (MkTensor x) (MkTensor x') = t0 $ BinaryElementwise op x x'
1191 |
1192 | ||| Element-wise equality. For example, `tensor [1, 2] /= tensor [1, 3]` is
1193 | ||| `tensor [True, False]`.
1194 | export
1195 | (==) : Tensor shape dtype -> Tensor shape dtype -> Tensor shape PRED
1196 | (==) = ewBinary' $ Compare Eq
1197 |
1198 | ||| Element-wise inequality. For example, `tensor [1, 2] /= tensor [1, 3]` is
1199 | ||| `tensor [False, True]`.
1200 | export
1201 | (/=) : Tensor shape dtype -> Tensor shape dtype -> Tensor shape PRED
1202 | (/=) = ewBinary' $ Compare Ne
1203 |
1204 | ||| Element-wise less than. For example, `tensor [1, 2, 3] < tensor [2, 2, 2]` is
1205 | ||| `tensor [True, False, False]`.
1206 | export
1207 | (<) : Ord dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape PRED
1208 | (<) = ewBinary' $ Compare Lt
1209 |
1210 | ||| Element-wise greater than. For example, `tensor [1, 2, 3] > tensor [2, 2, 2]` is
1211 | ||| `tensor [False, False, True]`.
1212 | export
1213 | (>) : Ord dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape PRED
1214 | (>) = ewBinary' $ Compare Gt
1215 |
1216 | ||| Element-wise less than or equal. For example, `tensor [1, 2, 3] <= tensor [2, 2, 2]`
1217 | ||| is `tensor [True, True, False]`.
1218 | export
1219 | (<=) : Ord dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape PRED
1220 | (<=) = ewBinary' $ Compare Le
1221 |
1222 | ||| Element-wise greater than or equal. For example,
1223 | ||| `tensor [1, 2, 3] >= tensor [2, 2, 2]` is `tensor [False, True, True]`.
1224 | export
1225 | (>=) : Ord dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape PRED
1226 | (>=) = ewBinary' $ Compare Ge
1227 |
1228 | ||| Element-wise boolean and. For example,
1229 | ||| `tensor [True, True, False, False] && tensor [True, False, True, False]` is
1230 | ||| `tensor [True, False, False, False]`.
1231 | export
1232 | (&&) : Tensor shape PRED -> Tensor shape PRED -> Tensor shape PRED
1233 | (&&) = ewBinary And
1234 |
1235 | namespace Semigroup
1236 |   export
1237 |   [All] Semigroup (Tensor shape PRED) where
1238 |     (<+>) = (&&)
1239 |
1240 | namespace Monoid
1241 |   export
1242 |   [All] {shape : _} -> Monoid (Tensor shape PRED) using Tensor.Semigroup.All where
1243 |     neutral = fill True
1244 |
1245 | ||| Element-wise boolean or. For example,
1246 | ||| `tensor [True, True, False, False] || tensor [True, False, True, False]` is
1247 | ||| `tensor [True, True, True, False]`.
1248 | export
1249 | (||) : Tensor shape PRED -> Tensor shape PRED -> Tensor shape PRED
1250 | (||) = ewBinary Or
1251 |
1252 | namespace Semigroup
1253 |   export
1254 |   [Any] Semigroup (Tensor shape PRED) where
1255 |     (<+>) = (||)
1256 |
1257 | namespace Monoid
1258 |   export
1259 |   [Any] {shape : _} -> Monoid (Tensor shape PRED) using Tensor.Semigroup.Any where
1260 |     neutral = fill False
1261 |
1262 | ||| Element-wise boolean negation. For example, `not (tensor [True, False])` is
1263 | ||| `tensor [False, True]`.
1264 | export
1265 | not : Tensor shape PRED -> Tensor shape PRED
1266 | not = ewUnary Not
1267 |
1268 | ||| Choose elements from two `Tensor`s based on a `Tensor` of predicates. For each element in the
1269 | ||| predicates, the output will use the corresponding element from `onTrue` if the element is
1270 | ||| truthy, else the element from `onFalse`. For example, for
1271 | ||| ```
1272 | ||| preds : Tensor [3] PRED
1273 | ||| preds = tensor [False, True, False]
1274 | |||
1275 | ||| onTrue : Tensor [3] S32
1276 | ||| onTrue = tensor [1, 2, 3]
1277 | |||
1278 | ||| onFalse : Tensor [3] S32
1279 | ||| onFalse = tensor [4, 5, 6]
1280 | ||| ```
1281 | ||| `select preds onTrue onFalse` is `tensor [4, 2, 6]`.
1282 | |||
1283 | ||| @onTrue The elements to choose where the predicate elements are truthy.
1284 | ||| @onFalse The elements to choose where the predicate elements are falsy.
1285 | export
1286 | select :
1287 |   Tensor shape PRED ->
1288 |   (onTrue, onFalse : Tensor shape dtype) ->
1289 |   Tensor shape dtype
1290 | select (MkTensor p) (MkTensor t) (MkTensor f) = t0 $ Select p t f
1291 |
1292 | ||| Use a scalar predicate to evaluate one of two branches. If the predicate is truthy,
1293 | ||| evaluate `onTrue`, else `onFalse`. Each branch is evaluated lazily; only one will be
1294 | ||| evaluated.
1295 | |||
1296 | ||| For example, for
1297 | ||| ```
1298 | ||| f : Tensor [] F64 -> Tag $ Tensor [] F64
1299 | ||| f x = if_ (x < 1.0) (pure $ cos x) (do x <- tag x; x * x)
1300 | ||| ```
1301 | ||| `f 0.0` produces `1.0`, and `f 4.0` produces `8.0`.
1302 | |||
1303 | ||| **Note:** Branches to `if_` are interpreted as constant StableHLO functions. The XLA plugins
1304 | ||| impose heuristic-based rules on variable capture in higher-order functions. We do not
1305 | ||| comprehensively understand these rules, but you *might* experience runtime errors if you capture
1306 | ||| variables in the branches, especially variables other than constants, or variables that depend
1307 | ||| on parameters to enclosing (StableHLO) scopes.
1308 | |||
1309 | ||| @onTrue The branch to evaluate if the predicate is truthy.
1310 | ||| @onFalse The branch to evaluate if the predicate is falsy.
1311 | export
1312 | if_ :
1313 |   {shape : _} -> {dtype : _} ->
1314 |   Tensor [] PRED ->
1315 |   (onTrue, onFalse : Tag $ Tensor shape dtype) ->
1316 |   Tag $ Tensor shape dtype
1317 | if_ (MkTensor pred) onTrue onFalse =
1318 |   pure $ t0 $ If (TensorType shape dtype) pred !(mkFn1 [] [] onTrue) !(mkFn1 [] [] onFalse)
1319 |
1320 | ||| The identity tensor, with inferred shape and element type. For example,
1321 | ||| ```
1322 | ||| x : Tensor [2, 2] S32
1323 | ||| x = identity
1324 | ||| ```
1325 | ||| is
1326 | ||| ```
1327 | ||| x : Tensor [2, 2] S32
1328 | ||| x = tensor [[1, 0],
1329 | |||             [0, 1]]
1330 | ||| ```
1331 | export
1332 | identity : {n : _} -> {dtype : _} -> Num dtype => Tensor [n, n] dtype
1333 | identity =
1334 |   let MkTensor x = iota 0 {shape = [n, n], dtype = U64} == iota 1
1335 |    in t0 $ Convert dtype [n, n] x
1336 |
1337 | -- see https://www.python.org/dev/peps/pep-0465/#precedence-and-associativity
1338 | export infixl 9 @@
1339 |
1340 | namespace Vector
1341 |   ||| Vector dot product with a tensor of any rank. The vector dot product is with the first axis of
1342 |   ||| the right-hand side tensor. For example `tensor [0, 1, 2] @@ tensor [-1, -3, -1]` is
1343 |   ||| `-1`.
1344 |   export
1345 |   (@@) : Num dtype => Tensor [S m] dtype -> Tensor [S m] dtype -> Tensor [] dtype
1346 |   (MkTensor x) @@ (MkTensor x') = t0 $ DotGeneral [] [] [0] [0] (TensorType [] dtype) x x'
1347 |
1348 | namespace Matrix
1349 |   ||| Matrix multiplication with a matrix or vector. Contraction is along the last axis of the first
1350 |   ||| and the first axis of the last. For example,
1351 |   ||| ```
1352 |   ||| x : Tensor [2, 3] S32
1353 |   ||| x = tensor [[-1, -2, -3],
1354 |   |||             [ 0,  1,  2]]
1355 |   |||
1356 |   ||| y : Tensor [3, 1] S32
1357 |   ||| y = tensor [[4, 0, 5]]
1358 |   |||
1359 |   ||| z : Tensor [2, 1] S32
1360 |   ||| z = x @@ y
1361 |   ||| ```
1362 |   ||| is
1363 |   ||| ```
1364 |   ||| z : Tensor [2, 1] S32
1365 |   ||| z = tensor [-19, 10]
1366 |   ||| ```
1367 |   export
1368 |   (@@) : Num dtype =>
1369 |          Tensor [n, S m] dtype ->
1370 |          Tensor (S m :: tl) dtype ->
1371 |          {auto 0 vectorTail : length tl `LTE` 1} ->
1372 |          Tensor (n :: tl) dtype
1373 |   (MkTensor x) @@ (MkTensor x') = t0 $ DotGeneral [] [] [1] [0] (TensorType (n :: tl) dtype) x x'
1374 |
1375 | ||| The output shape of a `dotGeneral` operation.
1376 | public export
1377 | contract : (lBatch, rBatch, lContract, rContract : List Nat) ->
1378 |            (ls, rs : Shape) ->
1379 |            {auto 0 lInBoundsBatch : All (flip InBounds ls) lBatch} ->
1380 |            {auto 0 rInBoundsBatch : All (flip InBounds rs) rBatch} ->
1381 |            {auto 0 lInBoundsContract : All (flip InBounds ls) lContract} ->
1382 |            {auto 0 rInBoundsContract : All (flip InBounds rs) rContract} ->
1383 |            Shape
1384 | contract lBatch rBatch lContract rContract ls rs =
1385 |   let lResultDims = deleteAt {inBounds = lInBoundsBatch ++ lInBoundsContract}
1386 |                              (lBatch ++ lContract) ls
1387 |       rResultDims = deleteAt {inBounds = rInBoundsBatch ++ rInBoundsContract}
1388 |                              (rBatch ++ rContract) rs
1389 |    in multiIndex lBatch ls ++ lResultDims ++ rResultDims
1390 |
1391 | ||| Matrix multiplication.
1392 | |||
1393 | ||| This is a much more general version of `(@@)`, in which you can specify any number of batch
1394 | ||| and contracting axes. Matrix multiplication is done over each contracting axis.
1395 | ||| The operation is vectorized over batch axes. For each contracting axis on the left-hand
1396 | ||| operand, there is one contracting axis on the right-hand operand. These can be different axes
1397 | ||| in each operand. The same is true for each batch axis.
1398 | |||
1399 | ||| For example, we can vectorize over a typical rank-two matrix multiplication as follows: given
1400 | ||| two inputs tensors
1401 | ||| ```
1402 | ||| let x : Tensor [3, 4, 5, 6] F64
1403 | |||     y : Tensor [3, 4, 6, 7] F64
1404 | ||| ```
1405 | ||| we do
1406 | ||| ```
1407 | ||| let z : Tensor [3, 4, 5, 7] F64 = dotGeneral [0, 1] [0, 1] [3] [2] x y
1408 | ||| ```
1409 | ||| Here, we vectorized over the first two axes `[0, 1]`, and do standard matrix multiplication
1410 | ||| over the remaining axes by specifying the axes 3 and 2 respectively as contracting axes. Notice
1411 | ||| how the batch axes appear once each at the start of the output shape, and the contracting axis
1412 | ||| disappears. Remaining axes appear in order from left to right.
1413 | |||
1414 | ||| Note this API is somewhat of a quickfix to bring general matrix multiplication to the tensor
1415 | |||   API. It is not thoroughly tested. Expect it to change in the future.
1416 | export
1417 | dotGeneral :
1418 |   Num dtype =>
1419 |   (lBatch, rBatch, lContract, rContract : List Nat) ->
1420 |   {auto 0 lUnique : unique (lBatch ++ lContract) = True} ->
1421 |   {auto 0 rUnique : unique (rBatch ++ rContract) = True} ->
1422 |   {auto 0 lInBoundsBatch : All (flip InBounds ls) lBatch} ->
1423 |   {auto 0 rInBoundsBatch : All (flip InBounds rs) rBatch} ->
1424 |   {auto 0 lInBoundsContract : All (flip InBounds ls) lContract} ->
1425 |   {auto 0 rInBoundsContract : All (flip InBounds rs) rContract} ->
1426 |   {auto 0 batchDimsEq : multiIndex lBatch ls = multiIndex rBatch rs} ->
1427 |   {auto 0 contractDimsEq : multiIndex lContract ls = multiIndex rContract rs} ->
1428 |   Tensor ls dtype ->
1429 |   Tensor rs dtype ->
1430 |   Tensor (contract lBatch rBatch lContract rContract ls rs) dtype
1431 | dotGeneral lb rb lc rc (MkTensor x) (MkTensor y) =
1432 |   let resultType = TensorType (contract lb rb lc rc ls rs) dtype
1433 |    in t0 $ DotGeneral lb rb lc rc resultType x y
1434 |
1435 | ||| Element-wise addition. For example, `tensor [1, 2] + tensor [3, 4]` is
1436 | ||| `tensor [4, 6]`.
1437 | export
1438 | (+) : Num dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape dtype
1439 | (+) = ewBinary Add
1440 |
1441 | namespace Semigroup
1442 |   export
1443 |   [Sum] Num dtype => Semigroup (Tensor shape dtype) where
1444 |     (<+>) = (+)
1445 |
1446 | namespace Monoid
1447 |   export
1448 |   [Sum] {shape : _} -> {dtype : _} -> Prelude.Num (idrisType dtype) => Num dtype =>
1449 |     Monoid (Tensor shape dtype) using Semigroup.Sum where
1450 |       neutral = fill 0
1451 |
1452 | ||| Element-wise negation. For example, `- tensor [1, -2]` is `tensor [-1, 2]`.
1453 | export
1454 | negate : Neg dtype => Tensor shape dtype -> Tensor shape dtype
1455 | negate $ MkTensor i = t0 $ UnaryElementwise Neg i
1456 |
1457 | ||| Element-wise subtraction. For example, `tensor [3, 4] - tensor [4, 2]` is
1458 | ||| `tensor [-1, 2]`.
1459 | export
1460 | (-) : Neg dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape dtype
1461 | (-) = ewBinary Sub
1462 |
1463 | ||| Element-wise multiplication. For example, `tensor [2, 3] * tensor [4, 5]` is
1464 | ||| `tensor [8, 15]`.
1465 | export
1466 | (*) : Num dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape dtype
1467 | (*) = ewBinary Mul
1468 |
1469 | namespace Semigroup
1470 |   export
1471 |   [Prod] Num dtype => Semigroup (Tensor shape dtype) where
1472 |     (<+>) = (*)
1473 |
1474 | namespace Monoid
1475 |   export
1476 |   [Prod] {shape : _} -> {dtype : _} -> Prelude.Num (idrisType dtype) => Num dtype =>
1477 |     Monoid (Tensor shape dtype) using Semigroup.Prod where
1478 |       neutral = fill 1
1479 |
1480 | ||| Element-wise floating point division. For example, `tensor [2, 3] / tensor [4, 5]` is
1481 | ||| `tensor [0.5, 0.6]`.
1482 | export
1483 | (/) : Fractional dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape dtype
1484 | (/) = ewBinary Div
1485 |
1486 | inf = tensor 1.0 / tensor 0.0
1487 | nan = tensor 0.0 / tensor 0.0
1488 |
1489 | ||| Element-wise division of natural numbers. For example,
1490 | ||| `div (tensor [13, 8]) [3, 4]` is `tensor [4, 2]`.
1491 | |||
1492 | ||| **Note:** Broadcasting a single value into a large `Literal` will be slower than for a `Tensor`.
1493 | ||| For this reason, if you're using a single common denominator, consider using `Scalarwise.div`.
1494 | export
1495 | div : Tensor shape U64 ->
1496 |       (denom : Literal shape Nat) ->
1497 |       {auto 0 isSucc : All IsSucc denom} ->
1498 |       Tensor shape U64
1499 | div x y with (x)
1500 |   _ | (MkTensor {shape = _} _) = ewBinary Div x (tensor {dtype = U64} $ cast <$> y)
1501 |
1502 | namespace Scalarwise
1503 |   ||| Overload of `div` for common denominator. The denominator is broadcast to match the numerator.
1504 |   export
1505 |   div :
1506 |     Tensor (d :: ds) U64 ->
1507 |     (denom : Nat) ->
1508 |     {auto 0 isSucc : IsSucc denom} ->
1509 |     Tensor (d :: ds) U64
1510 |   div x y with (x)
1511 |     _ | (MkTensor {shape = _} _) = ewBinary Div x (fill {dtype = U64} $ cast y)
1512 |
1513 | namespace Integral
1514 |   ||| Element-wise remainder for natural numbers. For example,
1515 |   ||| `rem (tensor [13, 8]) [3, 4]` is `tensor [1, 0]`.
1516 |   |||
1517 |   ||| **Note:** Broadcasting a single value into a large `Literal` will be slower than for a
1518 |   ||| `Tensor`. For this reason, if you're using a single common denominator, consider using
1519 |   ||| `Scalarwise.rem`.
1520 |   export
1521 |   rem : Tensor shape U64 ->
1522 |         (denom : Literal shape Nat) ->
1523 |         {auto 0 isSucc : All IsSucc denom} ->
1524 |         Tensor shape U64
1525 |   rem x y with (x)
1526 |     _ | (MkTensor {shape = _} _) = ewBinary Rem x (tensor {dtype = U64} $ cast <$> y)
1527 |
1528 |   namespace Scalarwise
1529 |     ||| Overload of `rem` for a common denominator. The denominator is broadcast to match the
1530 |     ||| numerator.
1531 |     export
1532 |     rem :
1533 |       Tensor (d :: ds) U64 ->
1534 |       (denom : Nat) ->
1535 |       {auto 0 isSucc : IsSucc denom} ->
1536 |       Tensor (d :: ds) U64
1537 |     rem x y with (x)
1538 |       _ | (MkTensor {shape = _} _) = ewBinary Rem x (fill {dtype = U64} $ cast y)
1539 |
1540 | ||| Each element in `base` raised to the power of the corresponding element in `exponent`.
1541 | ||| example, `pow (tensor [2, 25, -9]) (tensor [3, -0.5, 0.5])` is `tensor [8, 0.2, nan]`.
1542 | |||
1543 | ||| **Note:** The first root is used. Fractional powers of negative numbers return NaN.
1544 | export
1545 | pow : (base, exponent : Tensor shape F64) -> Tensor shape F64
1546 | pow = ewBinary Pow
1547 |
1548 | (>>) : Tensor shape U64 -> Tensor shape U64 -> Tensor shape U64
1549 | (>>) = ewBinary ShiftRightLogical
1550 |
1551 | ||| Element-wise, whether a number is *not* infinity or NaN.
1552 | export
1553 | isFinite : Tensor shape F64 -> Tensor shape PRED
1554 | isFinite = ewUnary' IsFinite
1555 |
1556 | ||| Element-wise sign. For example, `sign (tensor [-2, 0, 2, nan])` is `tensor [-1, 0, 1, nan]`.
1557 | export
1558 | sign : Neg dtype => Tensor shape dtype -> Tensor shape dtype
1559 | sign = ewUnary Sign
1560 |
1561 | ||| Element-wise absolute value. For example, `abs (tensor [-2, 3])` is `tensor [2, 3]`.
1562 | export
1563 | abs : Abs dtype => Tensor shape dtype -> Tensor shape dtype
1564 | abs = ewUnary Abs
1565 |
1566 | ||| The element-wise natural exponential. For example, `exp (tensor [-1, 0, 2])` is
1567 | ||| `tensor [1 / euler, 1, pow euler 2]`.
1568 | export
1569 | exp : Tensor shape F64 -> Tensor shape F64
1570 | exp = ewUnary Exp
1571 |
1572 | ||| The element-wise natural exponential, minus one, equivalent to `(`subtract` 1) . exp`.
1573 | export
1574 | expM1 : Tensor shape F64 -> Tensor shape F64
1575 | expM1 = ewUnary ExpM1
1576 |
1577 | ||| The element-wise floor function. For example,
1578 | ||| `floor (tensor [-1.6, -1.5, -1.4, -1.0, 1.0, 1.4, 1.5, 1.6])` is
1579 | ||| `tensor [-2.0, -2.0, -2.0, -1.0, 1.0, 1.0, 1.0, 1.0]`.
1580 | export
1581 | floor : Tensor shape F64 -> Tensor shape F64
1582 | floor = ewUnary Floor
1583 |
1584 | ||| The element-wise ceiling function. For example,
1585 | ||| `ceil (tensor [-1.6, -1.5, -1.4, -1.0, 1.0, 1.4, 1.5, 1.6])` is
1586 | ||| `tensor [-1.0, -1.0, -1.0, -1.0, 1.0, 2.0, 2.0, 2.0]`.
1587 | export
1588 | ceil : Tensor shape F64 -> Tensor shape F64
1589 | ceil = ewUnary Ceil
1590 |
1591 | public export
1592 | data BreakTies = AwayFromZero | ToEven
1593 |
1594 | ||| Round each element to the nearest integer, breaking ties according to the `BreakTies`.
1595 | |||
1596 | ||| `AwayFromZero` breaks ties away from zero, for example
1597 | ||| `round (tensor [-1.6, -1.5, -1.4, -1.0, -0.5, 0.1, 0.5, 1.0, 1.4, 1.5, 1.6])` is
1598 | ||| `tensor [-2.0, -2.0, -1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0]`.
1599 | |||
1600 | ||| `ToEven` breaks ties to the nearest even, for example,
1601 | ||| `round (tensor [-1.6, -1.5, -1.4, -1.0, -0.5, 0.5, 1.0, 1.4, 1.5, 1.6])` is
1602 | ||| `tensor [-2.0, -2.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0]`
1603 | export
1604 | round : BreakTies -> Tensor shape F64 -> Tensor shape F64
1605 | round AwayFromZero = ewUnary RoundAFZ
1606 | round ToEven = ewUnary RoundEven
1607 |
1608 | ||| The element-wise natural logarithm. Negative inputs yield NaN output. For example,
1609 | ||| `log (tensor [1 / euler, 1, euler * euler])` is `tensor [-1, 0, 2]`.
1610 | export
1611 | log : Tensor shape F64 -> Tensor shape F64
1612 | log = ewUnary Log
1613 |
1614 | ||| The element-wise natural logarithm of the input plus one, equivalent to `log . (+ 1)`.
1615 | ||| Inputs less than (-1) yield NaN.
1616 | export
1617 | log1p : Tensor shape F64 -> Tensor shape F64
1618 | log1p = ewUnary Log1p
1619 |
1620 | ||| The element-wise logistic function equivalent to `1 / 1 + exp (-x)`.
1621 | export
1622 | logistic : Tensor shape F64 -> Tensor shape F64
1623 | logistic = ewUnary Logistic
1624 |
1625 | ||| The element-wise sine.
1626 | export
1627 | sin : Tensor shape F64 -> Tensor shape F64
1628 | sin = ewUnary Sin
1629 |
1630 | ||| The element-wise cosine.
1631 | export
1632 | cos : Tensor shape F64 -> Tensor shape F64
1633 | cos = ewUnary Cos
1634 |
1635 | ||| The element-wise tangent.
1636 | export
1637 | tan : Tensor shape F64 -> Tensor shape F64
1638 | tan = ewUnary Tan
1639 |
1640 | ||| The element-wise arcsine.
1641 | export
1642 | asin : Tensor shape F64 -> Tensor shape F64
1643 | asin = ewUnary Asin
1644 |
1645 | ||| The element-wise arccosine.
1646 | export
1647 | acos : Tensor shape F64 -> Tensor shape F64
1648 | acos = ewUnary Acos
1649 |
1650 | ||| The element-wise arctangent.
1651 | export
1652 | atan : Tensor shape F64 -> Tensor shape F64
1653 | atan = ewUnary Atan
1654 |
1655 | ||| The element-wise two-argument arctangent: the angle between the vector (x, y) and the positive
1656 | ||| x-axis.
1657 | export
1658 | atan2 : (y, x : Tensor shape F64) -> Tensor shape F64
1659 | atan2 = ewBinary Atan2
1660 |
1661 | ||| The element-wise hyperbolic sine.
1662 | export
1663 | sinh : Tensor shape F64 -> Tensor shape F64
1664 | sinh = ewUnary Sinh
1665 |
1666 | ||| The element-wise hyperbolic cosine.
1667 | export
1668 | cosh : Tensor shape F64 -> Tensor shape F64
1669 | cosh = ewUnary Cosh
1670 |
1671 | ||| The element-wise hyperbolic tangent.
1672 | export
1673 | tanh : Tensor shape F64 -> Tensor shape F64
1674 | tanh = ewUnary Tanh
1675 |
1676 | ||| The element-wise hyperbolic arcsine.
1677 | export
1678 | asinh : Tensor shape F64 -> Tensor shape F64
1679 | asinh = ewUnary Asinh
1680 |
1681 | ||| The element-wise hyperbolic arccosine.
1682 | export
1683 | acosh : Tensor shape F64 -> Tensor shape F64
1684 | acosh = ewUnary Acosh
1685 |
1686 | ||| The element-wise hyperbolic arctangent.
1687 | export
1688 | atanh : Tensor shape F64 -> Tensor shape F64
1689 | atanh = ewUnary Atanh
1690 |
1691 | ||| An approximation to the element-wise error function.
1692 | export
1693 | erf : Tensor shape F64 -> Tensor shape F64
1694 | erf = ewUnary Erf
1695 |
1696 | erfInv : Tensor shape F64 -> Tensor shape F64
1697 | erfInv = ewUnary ErfInv
1698 |
1699 | ||| The element-wise square. For example, `square (tensor [-2, 0, 3])`
1700 | ||| is `tensor [4, 0, 9]`.
1701 | export
1702 | square : Tensor shape F64 -> Tensor shape F64
1703 | square = ewUnary Square
1704 |
1705 | ||| The element-wise square root. The first root is used. Negative inputs yield NaN output.
1706 | ||| For example, `sqrt (tensor [0, 9])` is `tensor [0, 3]`.
1707 | export
1708 | sqrt : Tensor shape F64 -> Tensor shape F64
1709 | sqrt = ewUnary Sqrt
1710 |
1711 | ||| The element-wise reciprocal square root. The first root is used. Negative inputs yield NaN output.
1712 | ||| For example, `rsqrt (tensor [0, 4])` is `tensor [inf, 0.5]`.
1713 | export
1714 | rsqrt : Tensor shape F64 -> Tensor shape F64
1715 | rsqrt = ewUnary Rsqrt
1716 |
1717 | ||| The element-wise cube root. The first root is used. Negative inputs yield negative outputs.
1718 | ||| For example, `cbrt (tensor [8, -27])` is `tensor [2, -3]`.
1719 | export
1720 | cbrt : Tensor shape F64 -> Tensor shape F64
1721 | cbrt = ewUnary Cbrt
1722 |
1723 | ||| The element-wise minimum of the first argument compared to the second. For example,
1724 | ||| `min (tensor [-3, -1, 3]) (tensor [-1, 0, 1])` is `tensor [-3, -1, 1]`.
1725 | export
1726 | min : Ord dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape dtype
1727 | min (MkTensor x) (MkTensor x') = t0 $ BinaryElementwise Min x x'
1728 |
1729 | namespace Semigroup
1730 |   export
1731 |   [Min] {shape : _} -> Ord dtype => Semigroup (Tensor shape dtype) where
1732 |     (<+>) = min
1733 |
1734 | namespace Monoid
1735 |   export
1736 |   [Min] {shape : _} -> {dtype : _} -> Ord dtype =>
1737 |     Monoid (Tensor shape dtype) using Semigroup.Min where
1738 |       neutral = broadcast max
1739 |
1740 | ||| The element-wise maximum of the first argument compared to the second. For example,
1741 | ||| `max (tensor [-3, -1, 3]) (tensor [-1, 0, 1])` is `tensor [-1, 0, 3]`.
1742 | export
1743 | max : Ord dtype => Tensor shape dtype -> Tensor shape dtype -> Tensor shape dtype
1744 | max (MkTensor x) (MkTensor x') = t0 $ BinaryElementwise Max x x'
1745 |
1746 | namespace Semigroup
1747 |   export
1748 |   [Max] Ord dtype => Semigroup (Tensor shape dtype) where
1749 |     (<+>) = max
1750 |
1751 | namespace Monoid
1752 |   export
1753 |   [Max] {shape : _} -> {dtype : _} -> Ord dtype =>
1754 |     Monoid (Tensor shape dtype) using Semigroup.Max where
1755 |       neutral = broadcast min
1756 |
1757 | ||| The diagonal of a matrix as a vector. For example, for
1758 | ||| ```
1759 | ||| x : Tensor [3, 3] S32
1760 | ||| x = tensor [[0, 1, 2],
1761 | |||             [3, 4, 5],
1762 | |||             [6, 7, 8]]
1763 | ||| ```
1764 | ||| `diag x` is `tensor [0, 4, 8]`.
1765 | export
1766 | diag : Num dtype => Prelude.Num (idrisType dtype) => Tensor [n, n] dtype -> Tensor [n] dtype
1767 | diag {n = 0} x@(MkTensor {shape = [0, 0]} _) = reshape x
1768 | diag {n = S n} x@(MkTensor {shape = [S n, S n]} _) = (x * identity) @@ fill 1
1769 |
1770 | argmxx :
1771 |   Ord dtype =>
1772 |   (Tensor [] dtype -> Tensor [] dtype -> Tensor [] PRED) ->
1773 |   Tensor [] dtype ->
1774 |   Tensor [S n] dtype ->
1775 |   Tag $ Tensor [] U64
1776 | argmxx cmp (MkTensor bound) x@(MkTensor {shape = _} _) = do
1777 |   let MkTensor idxs : Tensor [S n] U64 = iota 0
1778 |       MkTensor x = x
1779 |       MkTensor zero = tensor {dtype = U64} 0
1780 |
1781 |       mon :
1782 |         Tensor [] dtype -> Tensor [] U64 ->
1783 |         Tensor [] dtype -> Tensor [] U64 ->
1784 |         Tag (Tensor [] dtype, Tensor [] U64)
1785 |       mon x y x' y' =
1786 |         let useNext = x == x && (cmp x' x || x' /= x')
1787 |          in pure (select useNext x' x, select useNext y' y)
1788 |
1789 |   MkTagT $ do
1790 |     addr <- reserve
1791 |
1792 |     let MkTagT res = mon
1793 |           (MkTensor $ V 0 $ BoundSet addr)
1794 |           (MkTensor $ V 1 $ BoundSet addr)
1795 |           (MkTensor $ V 2 $ BoundSet addr)
1796 |           (MkTensor $ V 3 $ BoundSet addr)
1797 |         (env, (MkTensor m, MkTensor i)) = runState (emptyFrom !get) res
1798 |         argTys = [TensorType [] dtype, TensorType [] U64]
1799 |         f = MkFn addr (argTys ++ argTys) argTys [m, i] env
1800 |
1801 |     updateCounterFrom env
1802 |     pure $ MkTensor $ V 1 $ Concrete $ Reduce f [bound, zero] [0] [x, idxs]
1803 |
1804 | ||| The first index of the maximum value in a vector. For example,
1805 | ||| `argmax (tensor [-1, 3, -2, -2, 3])` produces `tensor 1`. If the vector contains NaN values,
1806 | ||| `argmax` returns the index of the first NaN.
1807 | export
1808 | argmax : Ord dtype => Tensor [S n] dtype -> Tag $ Tensor [] U64
1809 | argmax x@(MkTensor {dtype} _) = argmxx (>) min x
1810 |
1811 | ||| The first index of the minimum value in a vector. For example,
1812 | ||| `argmin (tensor [-1, 3, -2, -2, 3])` produces `tensor 2`. If the vector contains NaN values,
1813 | ||| `argmin` returns the index of the first NaN.
1814 | export
1815 | argmin : Ord dtype => Tensor [S n] dtype -> Tag $ Tensor [] U64
1816 | argmin x@(MkTensor {dtype} _) = argmxx (<) max x
1817 |
1818 | ||| Represents the upper- or lower-triangular component of a matrix.
1819 | public export
1820 | data Triangle = Upper | Lower
1821 |
1822 | ||| Get the upper- or lower-triangular component of a matrix, always including the matrix diagonal.
1823 | ||| Remaining elements will be zero. For example, for
1824 | ||| ```
1825 | ||| x : Tensor [3, 3] S32
1826 | ||| x = tensor [[1, 2, 3],
1827 | |||             [4, 5, 6],
1828 | |||             [7, 8, 9]]
1829 | ||| ```
1830 | ||| `triangle Lower x` produces
1831 | ||| ```
1832 | ||| x : Tensor [3, 3] S32
1833 | ||| x = tensor [[1, 0, 0],
1834 | |||             [4, 5, 0],
1835 | |||             [7, 8, 9]]
1836 | ||| ```
1837 | export
1838 | triangle :
1839 |   Prelude.Num (idrisType dtype) =>
1840 |   Triangle ->
1841 |   Tensor [n, n] dtype ->
1842 |   Tag $ Tensor [n, n] dtype
1843 | triangle tri (MkTensor x) = do
1844 |   let range : Tensor [n * n] U64 = iota 0
1845 |   indices <- tag $ reshape {to = [n, n], sizesEqual = productSquare n} range
1846 |   let op = case tri of
1847 |         Upper => Tensor.(>)
1848 |         Lower => Tensor.(<)
1849 |   pure $ select (op indices indices.T) (fill $ fromInteger 0) (MkTensor x)
1850 |
1851 |   where
1852 |
1853 |   productSquare : (m : Nat) -> product [m * m] = product [m, m]
1854 |   productSquare m =
1855 |     rewrite multOneRightNeutral (m * m) in
1856 |     rewrite multOneRightNeutral m in
1857 |     Refl
1858 |
1859 | ||| Cholesky decomposition. Computes the lower triangular matrix `L` from the symmetric, positive
1860 | ||| semi-definite matrix `X` s.t. `X = L @@ L.T`. Values will be NaN if the input matrix is not
1861 | ||| positive semi-definite. The remaining matrix components - those not in the lower triangle or
1862 | ||| diagonal - will always be zero.
1863 | export
1864 | cholesky : Tensor [S n, S n] F64 -> Tag $ Tensor [S n, S n] F64
1865 | cholesky $ MkTensor x = triangle Lower (t0 $ Cholesky x)
1866 |
1867 | export infix 9 |\, \|
1868 |
1869 | namespace Matrix
1870 |   ||| Solve the set of linear equations `a @@ x = b` for `x` where `a` is a lower-triangular matrix.
1871 |   ||| `a` is given by the lower-triangular elements of the first argument. Values in the
1872 |   ||| upper-triangular part are ignored. If `a` is lower-triangular already,
1873 |   ||| this is written `a |\ b`.
1874 |   |||
1875 |   ||| The operator is shaped like the lower-triangular portion of a matrix to signal that it uses
1876 |   ||| this portion of its argument. This is in contrast to `(\|)`.
1877 |   export
1878 |   (|\) : Tensor [m, m] F64 -> Tensor [m, n] F64 -> Tensor [m, n] F64
1879 |   (MkTensor a) |\ (MkTensor b) = t0 $ TriangularSolve a b True
1880 |
1881 |   ||| Solve the set of linear equations `a @@ x = b` for `x` where `a` is an upper-triangular
1882 |   ||| matrix. `a` is given by the upper-triangular elements of the first argument. Values in the
1883 |   ||| lower-triangular part are ignored. If `a` is upper-triangular already, this is written
1884 |   ||| `a \| b`.
1885 |   |||
1886 |   ||| The operator is shaped like the upper-triangular portion of a matrix to signal that it uses
1887 |   ||| this portion of its argument. This is in contrast to `(|\)`.
1888 |   export
1889 |   (\|) : Tensor [m, m] F64 -> Tensor [m, n] F64 -> Tensor [m, n] F64
1890 |   (MkTensor a) \| (MkTensor b) = t0 $ TriangularSolve a b False
1891 |
1892 | namespace Vector
1893 |   ||| Solve the set of linear equations `a @@ x = b` for `x` where `a` is a lower-triangular matrix.
1894 |   ||| `a` is given by the lower-triangular elements of the first argument. Values in the
1895 |   ||| upper-triangular part are ignored. If `a` is lower-triangular already,
1896 |   ||| this is written `a |\ b`.
1897 |   |||
1898 |   ||| The operator is shaped like the lower-triangular portion of a matrix to signal that it uses
1899 |   ||| this portion of its argument. This is in contrast to `(\|)`.
1900 |   export
1901 |   (|\) : Tensor [m, m] F64 -> Tensor [m] F64 -> Tensor [m] F64
1902 |   a |\ b = let (MkTensor {shape = [_]} _) = b in squeeze (a |\ expand 1 b)
1903 |
1904 |   ||| Solve the set of linear equations `a @@ x = b` for `x` where `a` is an upper-triangular
1905 |   ||| matrix. `a` is given by the upper-triangular elements of the first argument. Values in the
1906 |   ||| lower-triangular part are ignored. If `a` is upper-triangular already, this is written
1907 |   ||| `a \| b`.
1908 |   |||
1909 |   ||| The operator is shaped like the upper-triangular portion of a matrix to signal that it uses
1910 |   ||| this portion of its argument. This is in contrast to `(|\)`.
1911 |   export
1912 |   (\|) : Tensor [m, m] F64 -> Tensor [m] F64 -> Tensor [m] F64
1913 |   a \| b = let (MkTensor {shape = [_]} _) = b in squeeze (a \| expand 1 b)
1914 |
1915 | ||| Sum the elements along the diagonal of the input. For example,
1916 | ||| `trace (tensor [[-1, 5], [1, 4]])` produces `3`.
1917 | export
1918 | trace : Num dtype => Prelude.Num (idrisType dtype) =>
1919 |         Tensor [S n, S n] dtype ->
1920 |         Tag $ Tensor [] dtype
1921 | trace x with (x)
1922 |   _ | MkTensor {shape = [_, _]} _ = reduce @{Sum} [0, 1] $ x * identity
1923 |
1924 | ||| A `Rand a` produces a pseudo-random value of type `a` from a `Tensor [2] U64` state.
1925 | ||| The state is updated every time a new value is generated.
1926 | public export 0
1927 | Rand : Type -> Type
1928 | Rand = StateT (Tensor [2] U64) Tag
1929 |
1930 | ||| Generate independent and identically distributed (IID) uniform samples.
1931 | |||
1932 | ||| The generated samples are a deterministic function of the input key and state, but may vary
1933 | ||| between PJRT plugin and library version.
1934 | |||
1935 | ||| Example usage, multiplying two uniform samples
1936 | ||| ```
1937 | ||| x : Tag $ Tensor [3] U64
1938 | ||| x = let seed = tensor [1, 1] in evalStateT seed [| rng * rng |]
1939 | ||| ```
1940 | export
1941 | rng : {shape : _} -> Rand $ Tensor shape U64
1942 | rng = ST $ \(MkTensor state) => do
1943 |   res <- tag $ Concrete $ Rng state (TensorType shape U64)
1944 |   pure (MkTensor $ V 0 res, MkTensor $ V 1 res)
1945 |
1946 | ||| Generate independent and identically distributed (IID) from the uniform distribution U(0, 1).
1947 | |||
1948 | ||| The generated samples are a deterministic function of the input key and state, but may vary
1949 | ||| between PJRT plugin and library version.
1950 | |||
1951 | ||| Example usage, multiplying two uniform samples
1952 | ||| ```
1953 | ||| x : Rand $ Tensor [3] F64
1954 | ||| x = [| uniform * uniform |]
1955 | ||| ```
1956 | export
1957 | uniform : {shape : _} -> Rand $ Tensor shape F64
1958 | uniform =
1959 |   let numMantissaBits : Bits64 = 52
1960 |       scale = broadcast $ 2.0 `pow` tensor (Scalar $ - cast {to = Double} numMantissaBits)
1961 |       shift = fill $ 64 - numMantissaBits
1962 |    in rng {shape} <&> \x => castDtype (x >> shift) * scale
1963 |
1964 | ||| Generate independent and identically distributed (IID) samples from the standard normal
1965 | ||| distribution N(0, 1).
1966 | |||
1967 | ||| The generated samples are a deterministic function of the input key and state, but may vary
1968 | ||| between PJRT plugin and library version.
1969 | |||
1970 | ||| Example usage, multiplying two normal samples
1971 | ||| ```
1972 | ||| x : Rand $ Tensor [3] F64
1973 | ||| x = [| normal * normal |]
1974 | ||| ```
1975 | export
1976 | normal : {shape : _} -> Rand $ Tensor shape F64
1977 | normal = uniform <&> \x => sqrt (broadcast 2.0) * erfInv (broadcast 2.0 * x - broadcast 1.0)
1978 |