On this page:
2.4.1 Vectors and nested data
vector->device-vector
device-vector->vector
vector*->device-matrix
device-matrix->vector*
list*->device-array
vector*->device-array
device-array->list*
device-array->vector*
2.4.2 Packed numbers:   f32vectors, f64vectors and bytes
f32vector->device-vector
f64vector->device-vector
device-vector->f32vector
device-vector->f64vector
bytes->device-vector
device-vector->bytes
2.4.3 math/  matrix and math/  array
matrix->device-matrix
device-matrix->matrix
matrix->device-vector
device-vector->col-matrix
device-vector->row-matrix
array->device-array
device-array->array
2.4.4 From raft/  array
9.3

2.4 Conversions: raft/compat🔗ℹ

 (require raft/compat) package: raft

Conversions between device arrays and Racket data: the list and flvector conversions of raft/array, plus vectors, f32vectors, f64vectors, byte strings, and math/matrix and math/array values. raft does not re-export it, since it requires math-lib. See also Other forms of Racket data.

Racket value

  

To the GPU

  

Back to Racket

list

  

list->device-vector

  

device-vector->list

nested lists

  

list*->device-matrix, list*->device-array

  

device-matrix->list*, device-array->list*

vector

  

vector->device-vector

  

device-vector->vector

nested vectors

  

vector*->device-matrix, vector*->device-array

  

device-matrix->vector*, device-array->vector*

flvector

  

flvector->device-vector

  

device-vector->flvector

f32vector, f64vector

  

f32vector->device-vector, f64vector->device-vector

  

device-vector->f32vector, device-vector->f64vector

byte string

  

bytes->device-vector

  

device-vector->bytes

math/matrix matrix

  

matrix->device-matrix

  

device-matrix->matrix

row or column matrix

  

matrix->device-vector

  

device-vector->col-matrix, device-vector->row-matrix

math/array array, rank 1 or 2

  

array->device-array

  

device-array->array

The rules are those of Converting Racket data. Without #:dtype, the element type is inferred: exact integers give 'int64, other reals and empty data 'float64; an flvector, f64vector or flonum array gives 'float64, an f32vector 'float32. Exact rationals give 'float64, and booleans and integers from 263 to 264-1 are refused. Integer types truncate toward zero. A value the type cannot hold (a complex number, an infinity or NaN for an integer type, an out-of-range number) and a ragged row raise exn:fail:raft. #:layout sets the packing order on the host. Coming back, a conversion waits for the work queued on the array’s stream; floating-point elements become flonums, integers exact integers.

Rank. Device arrays have one or two axes; any other inferred rank raises exn:fail:raft.

Speed. An flvector, flonum array or f64vector sent as 'float64, an f32vector sent as 'float32, and a byte string are copied as they are; everything else is packed element by element.

2.4.1 Vectors and nested data🔗ℹ

procedure

(vector->device-vector xs    
  [#:dtype dtype    
  #:resources resources]) → device-vector?
  xs : (vectorof real?)
  dtype : (or/c #f 'float32 'float64 'int32 'int64) = #f
  resources : device-resources? = (current-device-resources)
Returns a vector of the elements of xs, of dtype or the inferred type.

Examples:
> (vector->device-vector #(3 1 4 1 5))

#<device-vector int64[5] cuda:0 [3 1 4 1 5]>

> (vector->device-vector #(0.5 1.5 2.5) #:dtype 'float32)

#<device-vector float32[3] cuda:0 [0.5 1.5 2.5]>

Weights in the type cuML takes:

> (define weights
    (for/vector ([i (in-range 6)])
      (/ 1.0 (add1 i))))
> (vector->device-vector weights #:dtype 'float32)

#<device-vector float32[6] cuda:0 [       1.0        0.5 0.33333334       0.25        0.2 0.16666667]>

One column of a table of vector rows:

> (define flowers
    (vector #("setosa" 5.1 3.5)
            #("versicolor" 7.0 3.2)
            #("virginica" 6.3 3.3)))
> (define lengths (vector-map (lambda (row) (vector-ref row 1)) flowers))
> (device-vector->list (vector->device-vector lengths))

'(5.1 7.0 6.3)

A string is refused:

> (vector->device-vector (vector-map (lambda (row) (vector-ref row 0)) flowers))

vector->device-vector: cannot infer a dtype: "setosa" is not

a real number

procedure

(device-vector->vector v) → (vectorof real?)

  v : device-vector?
Returns the elements of v as a new mutable vector: v.copy_to_host().tolist().

Example:
> (device-vector->vector (vector->device-vector #(2 7 1 8)))

'#(2 7 1 8)

Cluster sizes from labels:

> (define labels (vector->device-vector #(0 2 1 2 2 0) #:dtype 'int32))
> (define counts (make-vector 3 0))
> (for ([label (in-vector (device-vector->vector labels))])
    (vector-set! counts label (add1 (vector-ref counts label))))
> counts

'#(2 1 3)

The best score and its index:

> (define scores (device-vector->vector (vector->device-vector #(0.2 0.9 0.4))))
> (define best (vector-argmax values scores))
> (list best (vector-member best scores))

'(0.9 1)

procedure

(vector*->device-matrix rows    
  [#:dtype dtype    
  #:layout layout    
  #:resources resources]) → device-matrix?
  rows : (vectorof (vectorof real?))
  dtype : (or/c #f 'float32 'float64 'int32 'int64) = #f
  layout : (or/c 'row-major 'col-major) = 'row-major
  resources : device-resources? = (current-device-resources)
Like list*->device-matrix, for a vector of vector rows.

Example:
> (vector*->device-matrix #(#(1 2 3) #(4 5 6)))

#<device-matrix int64[2×3] row-major cuda:0

 [[1 2 3]

  [4 5 6]]>

A grid laid out by column:

> (define grid
    (for/vector ([x (in-range 3)])
      (for/vector ([y (in-range 2)])
        (+ (* 0.5 x) y))))
> (define G (vector*->device-matrix grid #:dtype 'float32 #:layout 'col-major))
> (list (shape G) (contiguous? G #:layout 'col-major) (strides G))

'((3 2) #t (1 3))

A ragged row is refused:

> (vector*->device-matrix #(#(1.0 2.0) #(3.0)))

vector*->device-matrix: row 1 has 1 element, but row 0 has

2: '#(3.0)

procedure

(device-matrix->vector* m) → (vectorof (vectorof real?))

  m : device-matrix?
Returns the rows of m as a vector of vectors, whatever its layout.

Example:
> (device-matrix->vector* (vector*->device-matrix #(#(1 2) #(3 4))))

'#(#(1 2) #(3 4))

One centroid of several:

> (define centroids (vector*->device-matrix #(#(5.0 3.4) #(6.6 3.0) #(5.9 2.8))))
> (vector-ref (device-matrix->vector* centroids) 1)

'#(6.6 3.0)

A column-major matrix still comes back as rows:

> (device-matrix->vector* G)

'#(#(0.0 1.0) #(0.5 1.5) #(1.0 2.0))

procedure

(list*->device-array xs    
  [#:dtype dtype    
  #:layout layout    
  #:resources resources]) → device-array?
  xs : 
(or/c (listof real?)
       (listof (or/c (listof real?) (vectorof real?))))
  dtype : (or/c #f 'float32 'float64 'int32 'int64) = #f
  layout : (or/c 'row-major 'col-major) = 'row-major
  resources : device-resources? = (current-device-resources)
Returns a vector for a list of numbers and a matrix for a list of rows (lists or vectors). If the first element is a row, every element must be one; a deeper nesting is refused. '() is an empty vector. layout is ignored for a vector.

Examples:
> (list*->device-array '(1.0 2.0 3.0))

#<device-vector float64[3] cuda:0 [1.0 2.0 3.0]>

> (list*->device-array '((1 2) (3 4)))

#<device-matrix int64[2×2] row-major cuda:0

 [[1 2]

  [3 4]]>

One call for a series or a table:

> (define (upload data)
    (list*->device-array data #:dtype 'float32))
> (map shape (list (upload '(0.5 1.5)) (upload '((0.5 1.5) (2.5 3.5) (4.5 5.5)))))

'((2) (3 2))

> (shape (list*->device-array '()))

'(0)

Other nestings are refused:

> (list*->device-array '(((1 2) (3 4))))

list*->device-array: rank 3 is not supported yet; rank 1 and

2 convert, and any rank arrives in leg 3

> (list*->device-array '(1.0 (2.0 3.0)))

list*->device-array: element 1 is a list, but element 0 is

not: '(2.0 3.0)

procedure

(vector*->device-array xs    
  [#:dtype dtype    
  #:layout layout    
  #:resources resources]) → device-array?
  xs : 
(or/c (vectorof real?)
       (vectorof (or/c (vectorof real?) (listof real?))))
  dtype : (or/c #f 'float32 'float64 'int32 'int64) = #f
  layout : (or/c 'row-major 'col-major) = 'row-major
  resources : device-resources? = (current-device-resources)
Like list*->device-array, for a vector of numbers or of rows (vectors or lists).

Examples:
> (vector*->device-array #(1 2 3))

#<device-vector int64[3] cuda:0 [1 2 3]>

> (vector*->device-array #(#(1 2) #(3 4)))

#<device-matrix int64[2×2] row-major cuda:0

 [[1 2]

  [3 4]]>

Data read back from a Racket literal:

> (define saved (read (open-input-string "#(#(0.1 0.2) #(0.3 0.4) #(0.5 0.6))")))
> (shape (vector*->device-array saved #:dtype 'float32))

'(3 2)

A non-row element is refused:

> (vector*->device-array (vector #(1 2) 3))

vector*->device-array: row 1 is not a list or vector, but

row 0 is: 3

procedure

(device-array->list* a)

 → (or/c (listof real?) (listof (listof real?)))
  a : device-array?
Returns the elements of a as a list, or a list of rows for a matrix: a.copy_to_host().tolist().

Examples:
> (device-array->list* (list*->device-array '(1 2 3)))

'(1 2 3)

> (device-array->list* (list*->device-array '((1 2) (3 4)) #:layout 'col-major))

'((1 2) (3 4))

Results as JSON, whatever their rank:

> (define (results->json a)
    (jsexpr->string (hasheq 'shape (shape a) 'values (device-array->list* a))))
> (results->json (list*->device-array '((1 2) (3 4)) #:dtype 'int32))

"{\"shape\":[2,2],\"values\":[[1,2],[3,4]]}"

> (results->json (vector->device-vector #(0.5 0.25)))

"{\"shape\":[2],\"values\":[0.5,0.25]}"

A sum over either rank:

> (define (total a)
    (define xs (device-array->list* a))
    (apply + (if (device-matrix? a) (apply append xs) xs)))
> (map total (list (list*->device-array '(1 2 3)) (list*->device-array '((1 2) (3 4)))))

'(6 10)

procedure

(device-array->vector* a)

 → (or/c (vectorof real?) (vectorof (vectorof real?)))
  a : device-array?
Like device-array->list*, building vectors.

Examples:
> (device-array->vector* (vector*->device-array #(1 2 3)))

'#(1 2 3)

> (device-array->vector* (vector*->device-array #(#(1 2) #(3 4))))

'#(#(1 2) #(3 4))

Indexing a result:

> (define table (device-array->vector* centroids))
> (vector-ref (vector-ref table 2) 0)

5.9

Sorting the host copy leaves the device array unchanged:

> (define distances (vector->device-vector #(2.5 0.5 1.5)))
> (vector-sort (device-array->vector* distances) <)

'#(0.5 1.5 2.5)

> (device-vector->list distances)

'(2.5 0.5 1.5)

2.4.2 Packed numbers: f32vectors, f64vectors and bytes🔗ℹ

procedure

(f32vector->device-vector xs 
  [#:dtype dtype 
  #:resources resources]) 
 → device-vector?
  xs : f32vector?
  dtype : (or/c 'float32 'float64 'int32 'int64) = 'float32
  resources : device-resources? = (current-device-resources)
Returns a vector of the elements of xs, of dtype.

Example:
> (f32vector->device-vector (f32vector 0.5 1.5 2.5))

#<device-vector float32[3] cuda:0 [0.5 1.5 2.5]>

Single-precision samples from an audio decoder:

> (define samples (make-f32vector 4 0.25))
> (f32vector-set! samples 2 -0.75)
> (define on-gpu (f32vector->device-vector samples))
> (list (dtype on-gpu) (device-vector->list on-gpu))

'(float32 (0.25 0.25 -0.75 0.25))

Widened, or truncated to integers:

> (device-vector->list (f32vector->device-vector (f32vector 0.1 2.7) #:dtype 'float64))

'(0.10000000149011612 2.700000047683716)

> (device-vector->list (f32vector->device-vector (f32vector 0.1 2.7) #:dtype 'int32))

'(0 2)

procedure

(f64vector->device-vector xs 
  [#:dtype dtype 
  #:resources resources]) 
 → device-vector?
  xs : f64vector?
  dtype : (or/c 'float32 'float64 'int32 'int64) = 'float64
  resources : device-resources? = (current-device-resources)
Returns a vector of the elements of xs, of dtype. A value too large for 'float32 raises exn:fail:raft.

Example:
> (f64vector->device-vector (f64vector 1.0 2.0 3.0))

#<device-vector float64[3] cuda:0 [1.0 2.0 3.0]>

Readings a C library filled, narrowed for cuML:

> (define readings (list->f64vector '(21.5 21.75 22.0 22.5)))
> (f64vector->device-vector readings #:dtype 'float32)

#<device-vector float32[4] cuda:0 [ 21.5 21.75  22.0  22.5]>

Doubles sent as integers:

> (dtype (f64vector->device-vector (f64vector 3.0 0.0 12.0) #:dtype 'int64))

'int64

Returns the elements of v as a new f32vector. A 'float64 value too large for 'float32 raises exn:fail:raft.

Example:

For a C library that takes float*:

> (define out (device-vector->f32vector (vector->device-vector #(0.1 0.2))))
> (list (f32vector-length out) (f32vector-ref out 0))

'(2 0.10000000149011612)

Integer labels as floats:

> (f32vector->list (device-vector->f32vector labels))

'(0.0 2.0 1.0 2.0 2.0 0.0)

Returns the elements of v as a new f64vector.

Example:
> (f64vector->list (device-vector->f64vector (f64vector->device-vector readings)))

'(21.5 21.75 22.0 22.5)

A 'float32 vector widens:

> (f64vector->list (device-vector->f64vector (vector->device-vector #(0.1) #:dtype 'float32)))

'(0.10000000149011612)

Summed on the host:

> (define totals (device-vector->f64vector (vector->device-vector #(1.5 2.5 3.0))))
> (for/sum ([i (in-range (f64vector-length totals))]) (f64vector-ref totals i))

7.0

procedure

(bytes->device-vector bs    
  #:dtype dtype    
  [#:resources resources]) → device-vector?
  bs : bytes?
  dtype : (or/c 'float32 'float64 'int32 'int64)
  resources : device-resources? = (current-device-resources)
Returns a vector whose storage is bs, read as dtype in the machine’s byte order. The length of bs must be a whole number of elements.

Examples:
> (define raw (bytes-append (real->floating-point-bytes 0.5 4)
                            (real->floating-point-bytes 1.5 4)))
> (bytes->device-vector raw #:dtype 'float32)

#<device-vector float32[2] cuda:0 [0.5 1.5]>

Labels from a binary file:

> (define label-file (make-temporary-file))
> (define label-bytes
    (apply bytes-append (for/list ([label (in-list '(0 2 1 1))])
                          (integer->integer-bytes label 4 #t))))
> (display-to-file label-bytes label-file #:exists 'truncate)
> (device-vector->list (bytes->device-vector (file->bytes label-file) #:dtype 'int32))

'(0 2 1 1)

A partial element is refused:

> (bytes->device-vector (make-bytes 6) #:dtype 'float32)

bytes->device-vector: 6 bytes do not hold a whole number of

4-byte float32 elements

procedure

(device-vector->bytes v) → bytes?

  v : device-vector?
Returns the storage of v as a new byte string in the machine’s byte order: v.copy_to_host().tobytes().

Example:
> (device-vector->bytes (vector->device-vector #(1 2) #:dtype 'int32))

#"\1\0\0\0\2\0\0\0"

A round trip through a file:

> (define result-file (make-temporary-file))
> (display-to-file (device-vector->bytes (vector->device-vector #(0.5 0.25))) result-file
                   #:exists 'truncate)
> (file-size result-file)

16

> (device-vector->list (bytes->device-vector (file->bytes result-file) #:dtype 'float64))

'(0.5 0.25)

Reinterpreted as another element type:

> (define one (device-vector->bytes (vector->device-vector #(1.0) #:dtype 'float32)))
> (device-vector->list (bytes->device-vector one #:dtype 'int32))

'(1065353216)

2.4.3 math/matrix and math/array🔗ℹ

A flonum array or mutable array hands over its storage in one step; any other array is read through a Typed Racket contract per element. Results come back as flonum arrays (FlArray) for floating-point device arrays and mutable arrays of exact integers for integer ones.

procedure

(matrix->device-matrix m    
  [#:dtype dtype    
  #:layout layout    
  #:resources resources]) → device-matrix?
  m : matrix?
  dtype : (or/c #f 'float32 'float64 'int32 'int64) = #f
  layout : (or/c 'row-major 'col-major) = 'row-major
  resources : device-resources? = (current-device-resources)
Returns a device matrix holding m, of dtype or the inferred type, packed in layout.

Example:
> (matrix->device-matrix (matrix [[1.0 2.0] [3.0 4.0]]))

#<device-matrix float64[2×2] row-major cuda:0

 [[1.0 2.0]

  [3.0 4.0]]>

A Gram matrix in single precision:

> (define A (matrix [[1.0 2.0] [3.0 4.0] [5.0 6.0]]))
> (define gram (matrix* (matrix-transpose A) A))
> (matrix->device-matrix gram #:dtype 'float32)

#<device-matrix float32[2×2] row-major cuda:0

 [[35.0 44.0]

  [44.0 56.0]]>

Exact entries infer 'int64; ask for the type you need:

> (dtype (matrix->device-matrix (identity-matrix 3)))

'int64

> (define I (matrix->device-matrix (identity-matrix 3) #:dtype 'float64 #:layout 'col-major))
> (list (dtype I) (contiguous? I #:layout 'col-major))

'(float64 #t)

procedure

(device-matrix->matrix m) → array?

  m : device-matrix?
Returns m as a two-axis math/array array, whatever its layout. A matrix with an extent of 0 gives an empty array, which matrix? rejects.

Example:
> (device-matrix->matrix (matrix->device-matrix (matrix [[1.0 2.0] [3.0 4.0]])))

(flarray #[#[1.0 2.0] #[3.0 4.0]])

Host algebra on the result:

> (define back (device-matrix->matrix (matrix->device-matrix gram)))
> (list (matrix-trace back) (matrix-determinant back))

'(91.0 24.0)

Integer matrices stay exact:

> (define counts-matrix (device-matrix->matrix (list*->device-matrix '((2 1) (1 3)) #:dtype 'int32)))
> (matrix-inverse counts-matrix)

(array #[#[3/5 -1/5] #[-1/5 2/5]])

procedure

(matrix->device-vector m    
  [#:dtype dtype    
  #:resources resources]) → device-vector?
  m : matrix?
  dtype : (or/c #f 'float32 'float64 'int32 'int64) = #f
  resources : device-resources? = (current-device-resources)
Returns a device vector of the elements of m, a row or column matrix; any other shape raises exn:fail:raft.

Examples:
> (matrix->device-vector (col-matrix [1 2 3]))

#<device-vector int64[3] cuda:0 [1 2 3]>

> (matrix->device-vector (row-matrix [0.5 1.5]))

#<device-vector float64[2] cuda:0 [0.5 1.5]>

A host-solved linear system:

> (define x (matrix-solve (matrix [[2.0 1.0] [1.0 3.0]]) (col-matrix [3.0 5.0])))
> (matrix->device-vector x #:dtype 'float32)

#<device-vector float32[2] cuda:0 [0.8 1.4]>

> (matrix->device-vector gram)

matrix->device-vector: a 2×2 matrix is neither a row nor a

column matrix

procedure

(device-vector->col-matrix v) → array?

  v : device-vector?
Returns v as a column matrix, of shape (vector n 1).

Example:
> (device-vector->col-matrix (vector->device-vector #(1.0 2.0 3.0)))

(flarray #[#[1.0] #[2.0] #[3.0]])

Checking a result on the host:

> (define coefficients (vector->device-vector #(1.0 -1.0)))
> (matrix* A (device-vector->col-matrix coefficients))

(array #[#[-1.0] #[-1.0] #[-1.0]])

A Euclidean norm:

> (matrix-norm (device-vector->col-matrix (vector->device-vector #(3.0 4.0))))

5.0

procedure

(device-vector->row-matrix v) → array?

  v : device-vector?
Returns v as a row matrix, of shape (vector 1 n).

Example:
> (device-vector->row-matrix (vector->device-vector #(1 2 3)))

(mutable-array #[#[1 2 3]])

Stacking results into one matrix:

> (define runs (list (vector->device-vector #(0.25 0.5)) (vector->device-vector #(0.75 1.0))))
> (matrix-stack (map device-vector->row-matrix runs))

(array #[#[0.25 0.5] #[0.75 1.0]])

A dot product as row times column:

> (define u (vector->device-vector #(1.0 2.0)))
> (matrix* (device-vector->row-matrix u) (device-vector->col-matrix u))

(array #[#[5.0]])

procedure

(array->device-array arr    
  [#:dtype dtype    
  #:layout layout    
  #:resources resources]) → device-array?
  arr : array?
  dtype : (or/c #f 'float32 'float64 'int32 'int64) = #f
  layout : (or/c 'row-major 'col-major) = 'row-major
  resources : device-resources? = (current-device-resources)
Returns a device vector for a one-axis array and a device matrix for a two-axis one, of dtype or the inferred type; layout applies to a matrix. Another rank raises exn:fail:raft.

Examples:
> (array->device-array (flarray #[#[1.0 2.0] #[3.0 4.0]]))

#<device-matrix float64[2×2] row-major cuda:0

 [[1.0 2.0]

  [3.0 4.0]]>

> (array->device-array (array #[1 2 3]))

#<device-vector int64[3] cuda:0 [1 2 3]>

A build-array table, read element by element:

> (define distances-table
    (build-array #(3 3) (lambda (js) (abs (- (vector-ref js 0) (vector-ref js 1))))))
> (array->device-array distances-table #:dtype 'float32)

#<device-matrix float32[3×3] row-major cuda:0

 [[0.0 1.0 2.0]

  [1.0 0.0 1.0]

  [2.0 1.0 0.0]]>

Columns sliced on the host first:

> (define measurements (flarray #[#[5.1 3.5 1.4] #[7.0 3.2 4.7] #[6.3 3.3 6.0]]))
> (define first-two (array-slice-ref measurements (list (::) (:: 0 2))))
> (device-array->list* (array->device-array first-two))

'((5.1 3.5) (7.0 3.2) (6.3 3.3))

> (array->device-array (array #[#[#[1 2]]]))

array->device-array: rank 3 is not supported yet; rank 1 and

2 convert, and any rank arrives in leg 3

procedure

(device-array->array a) → array?

  a : device-array?
Returns a as a math/array array of the same shape.

Examples:
> (device-array->array (vector->device-vector #(1.5 2.5)))

(flarray #[1.5 2.5])

> (device-array->array (list*->device-matrix '((1 2) (3 4)) #:dtype 'int32))

(mutable-array #[#[1 2] #[3 4]])

Summing a result:

> (array-all-sum (device-array->array (vector->device-vector #(0.5 1.5 2.0))))

4.0

Host arithmetic, sent back:

> (define scaled (array-scale (device-array->array (vector->device-vector #(1.0 2.0 3.0))) 10.0))
> (array->device-array scaled)

#<device-vector float64[3] cuda:0 [10.0 20.0 30.0]>

2.4.4 From raft/array🔗ℹ

Re-exported from Converting Racket data: