Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/antlobach/clorch/llms.txt

Use this file to discover all available pages before exploring further.

Clorch exposes tensor indexing through a single function, torch/ix, that accepts a tensor followed by one indexer per dimension. Every PyTorch indexing pattern — from a simple integer access to a reversed multi-dimensional slice — has a direct ix equivalent. This guide provides a structured translation reference so you can convert Python notebooks and research implementations into idiomatic Clorch code without guessing.

Quick Reference

The table below maps common PyTorch expressions to their Clorch equivalents.
PyTorchClorchDescription
t[0](ix t 0)Single element
t[-1](ix t -1)Last element
t[0, 1](ix t 0 1)Multi-dimensional
t[:, :](ix t :all :all)Select all dimensions
t[0:5](ix t [0 5])Range slice
t[:5](ix t [nil 5])From start
t[5:](ix t [5 nil])To end
t[::2](ix t [nil nil 2])Every 2nd element
t[1:8:2](ix t [1 8 2])Step slice
t[::-1](ix t [nil nil -1])Reverse entire tensor
t[5::-1](ix t [5 nil -1])Reverse from index 5
t[..., 0](ix t (quote ...) 0)Ellipsis
t[0, ...](ix t 0 (quote ...))Ellipsis at end

Basic Indexing

1D Tensors

Integer indexing extracts a single scalar. Negative indices count from the end. All scalar results are returned as floats by default.
(require '[clorch.torch :as torch])

(def x (torch/tensor [10 11 12 13 14]))

(torch/ix x 0)   ;; → 10.0
(torch/ix x 1)   ;; → 11.0
(torch/ix x -1)  ;; → 14.0  (last element)
(torch/ix x -2)  ;; → 13.0  (second to last)

Multi-dimensional Tensors

Pass one indexer per dimension. Providing fewer indexers than dimensions selects the full remaining dimensions.
(def x (torch/tensor [[1 2 3]
                      [4 5 6]
                      [7 8 9]]))

(torch/ix x 0)        ;; → [1.0, 2.0, 3.0]   (first row)
(torch/ix x -1)       ;; → [7.0, 8.0, 9.0]   (last row)
(torch/ix x 0 0)      ;; → 1.0
(torch/ix x 0 1)      ;; → 2.0
(torch/ix x :_ 0)     ;; → [1.0, 4.0, 7.0]   (first column)
(torch/ix x :_ -1)    ;; → [3.0, 6.0, 9.0]   (last column)

Slicing

Basic Ranges

A two-element vector [start stop] selects elements from start (inclusive) to stop (exclusive), matching Python’s exclusive-stop convention.
(def y (torch/tensor (range 10)))  ;; [0 1 2 3 4 5 6 7 8 9]

(torch/ix y [2 5])    ;; → [2.0, 3.0, 4.0]
(torch/ix y [0 4])    ;; → [0.0, 1.0, 2.0, 3.0]
(torch/ix y [6 10])   ;; → [6.0, 7.0, 8.0, 9.0]

Open-Ended Ranges

Use nil in place of a bound to leave it open. [start nil] runs to the end; [nil stop] starts from the beginning.
(torch/ix y [5 nil])    ;; → [5.0, 6.0, 7.0, 8.0, 9.0]  (last 5)
(torch/ix y [nil 5])    ;; → [0.0, 1.0, 2.0, 3.0, 4.0]  (first 5)
(torch/ix y [nil nil])  ;; → [0.0, ..., 9.0]             (all)

Step Slices

A three-element vector [start stop step] applies a stride. Either or both of start and stop may be nil to leave that bound open.
(torch/ix y [nil nil 2])   ;; → [0.0, 2.0, 4.0, 6.0, 8.0]  (every 2nd)
(torch/ix y [1 nil 2])     ;; → [1.0, 3.0, 5.0, 7.0, 9.0]  (every 2nd from 1)
(torch/ix y [1 8 2])       ;; → [1.0, 3.0, 5.0, 7.0]        (every 2nd, range 1–8)
(torch/ix y [nil nil 3])   ;; → [0.0, 3.0, 6.0, 9.0]        (every 3rd)

Negative Step Slicing (Reversing)

A negative step reverses traversal order. [nil nil -1] is the full reversal; [start nil -1] reverses from a given index down to zero.
(def t (torch/tensor (range 10)))

;; Full reverse
(torch/ix t [nil nil -1])    ;; → [9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0]

;; From index 5 back to start
(torch/ix t [5 nil -1])      ;; → [5.0, 4.0, 3.0, 2.0, 1.0, 0.0]

;; Partial reverse: indices 5, 4, 3 (stop=2 is exclusive)
(torch/ix t [5 2 -1])        ;; → [5.0, 4.0, 3.0]

;; Reverse every 2nd element
(torch/ix t [nil nil -2])    ;; → [9.0, 7.0, 5.0, 3.0, 1.0]

;; Reverse every 3rd element
(torch/ix t [nil nil -3])    ;; → [9.0, 6.0, 3.0, 0.0]

2D Tensor Examples

Multi-dimensional slicing combines one indexer per axis, separated by spaces.
(def x (torch/tensor [[0 1 2 3]
                      [4 5 6 7]
                      [8 9 10 11]]))

;; Rows 0–1, columns 1–2
(torch/ix x [0 2] [1 3])       ;; → [[1.0, 2.0], [5.0, 6.0]]

;; All rows, last two columns
(torch/ix x :all [2 4])        ;; → [[2.0, 3.0], [6.0, 7.0], [10.0, 11.0]]

;; Row 0, columns 1 to end
(torch/ix x 0 [1 4])           ;; → [1.0, 2.0, 3.0]

;; Every 2nd row, all columns
(torch/ix x [0 3 2] :all)      ;; → [[0.0, 1.0, 2.0, 3.0], [8.0, 9.0, 10.0, 11.0]]

Reversing Rows and Columns

(def m (torch/tensor [[1 2 3 4]
                      [5 6 7 8]
                      [9 10 11 12]]))

;; Reverse rows
(torch/ix m [nil nil -1] :_)
;; → [[9.0, 10.0, 11.0, 12.0],
;;    [5.0, 6.0, 7.0, 8.0],
;;    [1.0, 2.0, 3.0, 4.0]]

;; Reverse columns
(torch/ix m :_ [nil nil -1])
;; → [[4.0, 3.0, 2.0, 1.0],
;;    [8.0, 7.0, 6.0, 5.0],
;;    [12.0, 11.0, 10.0, 9.0]]

;; Reverse both axes
(torch/ix m [nil nil -1] [nil nil -1])
;; → [[12.0, 11.0, 10.0, 9.0],
;;    [8.0, 7.0, 6.0, 5.0],
;;    [4.0, 3.0, 2.0, 1.0]]

The ix Function: Indexer Type Reference

torch/ix accepts a tensor and any number of indexers — one per dimension you want to slice.

Indexer Syntax Summary

Clorch SyntaxMeaning
0, 1, -1Integer index — extracts a scalar, reduces dimensionality
:allSelect entire dimension
:_Select entire dimension (alternative spelling)
(quote ...)Ellipsis — fills all remaining unspecified dimensions
[start stop]Slice from start (inclusive) to stop (exclusive)
[start stop step]Slice with positive step
[nil stop]From index 0 to stop
[start nil]From start to end of dimension
[nil nil step]Every step-th element, full dimension
[nil nil -1]Reverse entire dimension
[nil nil -2]Reverse every 2nd element
[start nil -1]Reverse from start down to index 0

Advanced Indexing

Ellipsis

The ellipsis fills all unspecified dimensions between explicitly indexed ones. Use (quote ...) or the reader shorthand '... in scripts.
(def t3d (torch/reshape (torch/tensor (range 24)) [2 3 4]))

;; First element along dimension 0, all others
(torch/ix t3d 0 (quote ...))    ;; → shape [3, 4]

;; All along first dims, first element of last dim
(torch/ix t3d (quote ...) 0)    ;; → shape [2, 3]

;; Specific position with middle dimensions filled
(torch/ix t3d 1 (quote ...) 2)  ;; → shape [3]

Select-All Identity

:all and :_ are interchangeable. Using them on every dimension returns the tensor unchanged.
(def t (torch/tensor [[1 2 3]
                      [4 5 6]]))

(torch/ix t :all :all)   ;; → full tensor
(torch/ix t :_ :_)       ;; → full tensor (same result)

Integer Tensor (Fancy) Indexing

Pass a tensor with dtype :int64 as an indexer to perform gather-style selection.
(def m (torch/tensor [[1 2 3]
                      [4 5 6]
                      [7 8 9]
                      [10 11 12]]))

(def idx (torch/tensor [0 2 0 1] {:dtype :int64}))

(torch/ix m idx)        ;; → shape [4, 3]  — rows 0, 2, 0, 1
(torch/ix m :_ idx)     ;; → shape [4, 4]  — columns by index

Boolean Mask Indexing

Pass a boolean tensor to select elements where the mask is true.
(def t (torch/tensor [1 2 3 4 5]))
(def mask (torch/tensor [false false true true true] {:dtype :bool}))

(torch/ix t mask)   ;; → [3.0, 4.0, 5.0]

Helper Pattern: Tensor to Clojure Vector

When you need to work with slice results in pure Clojure, convert with item-float and tseq.
(defn tensor->vec [t]
  (mapv torch/item-float (torch/tseq t)))

(defn tensor->vecs [t]
  (mapv #(mapv torch/item-float (torch/tseq %)) (torch/tseq t)))

;; Usage
(def x (torch/tensor [1 2 3]))
(tensor->vec (torch/ix x [0 2]))   ;; → [1.0 2.0]

Real-World Patterns

(def data (torch/tensor (range 100)))
(def split-point 80)

(def train (torch/ix data [0 split-point]))
(def test  (torch/ix data [split-point nil]))
(def batch-data (torch/tensor (range 100)))
(def batch-size 16)
(def batch-idx 2)

(def start (* batch-idx batch-size))
(def end (+ start batch-size))

(torch/ix batch-data [start end])
(def sequence (torch/tensor (range 20)))
(def window-size 5)
(def stride 3)

;; Window at offset
(defn window [offset]
  (torch/ix sequence [offset (+ offset window-size)]))

(window 0)  ;; → [0.0, 1.0, 2.0, 3.0, 4.0]
(window 3)  ;; → [3.0, 4.0, 5.0, 6.0, 7.0]

Important Notes

Float results. Scalar extractions via integer indexing return double values. Use torch/item-float to extract a Clojure number from a 0-dimensional tensor result.
nil vs ::. Slice vectors use nil to denote open bounds, not Clojure’s auto-qualified :: keywords, which would conflict with the keyword indexer namespace.
Ellipsis quoting. The bare symbol ... is a valid Clojure symbol but may be read differently at the REPL versus in compiled source. Always use (quote ...) or the '... reader macro inside scripts to guarantee correct behavior.
Run the full example file to verify every slice operation in one pass:
clojure -M -e "(load-file \"examples/slicing_examples.clj\")"

Build docs developers (and LLMs) love