You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by we...@apache.org on 2018/10/31 21:32:29 UTC
[arrow] branch master updated: ARROW-3640: [Go] implement Tensors
This is an automated email from the ASF dual-hosted git repository.
wesm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new 2cdc4d4 ARROW-3640: [Go] implement Tensors
2cdc4d4 is described below
commit 2cdc4d4119ac611e33a80e849217779f77e8ebb0
Author: Sebastien Binet <bi...@cern.ch>
AuthorDate: Wed Oct 31 17:31:45 2018 -0400
ARROW-3640: [Go] implement Tensors
Author: Sebastien Binet <bi...@cern.ch>
Closes #2860 from sbinet/issue-3640 and squashes the following commits:
e88c21994 <Sebastien Binet> ARROW-3640: implement Tensors
7f7ad787e <Sebastien Binet> make numeric types implement FixedWidthDataType
---
go/arrow/array/data.go | 8 +-
go/arrow/datatype_numeric.gen.go | 50 +-
go/arrow/datatype_numeric.gen.go.tmpl | 3 +-
go/arrow/datatype_numeric.gen.go.tmpldata | 42 +-
go/arrow/doc.go | 2 +-
go/arrow/example_test.go | 87 +++
go/arrow/tensor/numeric.gen.go | 277 +++++++++
go/arrow/tensor/numeric.gen.go.tmpl | 55 ++
go/arrow/tensor/numeric.gen_test.go | 980 ++++++++++++++++++++++++++++++
go/arrow/tensor/numeric.gen_test.go.tmpl | 126 ++++
go/arrow/tensor/tensor.go | 239 ++++++++
go/arrow/tensor/tensor_test.go | 162 +++++
12 files changed, 1995 insertions(+), 36 deletions(-)
diff --git a/go/arrow/array/data.go b/go/arrow/array/data.go
index f4dea17..58b1648 100644
--- a/go/arrow/array/data.go
+++ b/go/arrow/array/data.go
@@ -85,9 +85,11 @@ func (d *Data) Release() {
}
}
-func (d *Data) DataType() arrow.DataType { return d.dtype }
-func (d *Data) NullN() int { return d.nulls }
-func (d *Data) Len() int { return d.length }
+func (d *Data) DataType() arrow.DataType { return d.dtype }
+func (d *Data) NullN() int { return d.nulls }
+func (d *Data) Len() int { return d.length }
+func (d *Data) Offset() int { return d.offset }
+func (d *Data) Buffers() []*memory.Buffer { return d.buffers }
// NewSliceData returns a new slice that shares backing data with the input.
// The returned Data slice starts at i and extends j-i elements, such as:
diff --git a/go/arrow/datatype_numeric.gen.go b/go/arrow/datatype_numeric.gen.go
index 30537be..2ec4c40 100644
--- a/go/arrow/datatype_numeric.gen.go
+++ b/go/arrow/datatype_numeric.gen.go
@@ -20,53 +20,63 @@ package arrow
type Int8Type struct{}
-func (t *Int8Type) ID() Type { return INT8 }
-func (t *Int8Type) Name() string { return "int8" }
+func (t *Int8Type) ID() Type { return INT8 }
+func (t *Int8Type) Name() string { return "int8" }
+func (t *Int8Type) BitWidth() int { return 8 }
type Int16Type struct{}
-func (t *Int16Type) ID() Type { return INT16 }
-func (t *Int16Type) Name() string { return "int16" }
+func (t *Int16Type) ID() Type { return INT16 }
+func (t *Int16Type) Name() string { return "int16" }
+func (t *Int16Type) BitWidth() int { return 16 }
type Int32Type struct{}
-func (t *Int32Type) ID() Type { return INT32 }
-func (t *Int32Type) Name() string { return "int32" }
+func (t *Int32Type) ID() Type { return INT32 }
+func (t *Int32Type) Name() string { return "int32" }
+func (t *Int32Type) BitWidth() int { return 32 }
type Int64Type struct{}
-func (t *Int64Type) ID() Type { return INT64 }
-func (t *Int64Type) Name() string { return "int64" }
+func (t *Int64Type) ID() Type { return INT64 }
+func (t *Int64Type) Name() string { return "int64" }
+func (t *Int64Type) BitWidth() int { return 64 }
type Uint8Type struct{}
-func (t *Uint8Type) ID() Type { return UINT8 }
-func (t *Uint8Type) Name() string { return "uint8" }
+func (t *Uint8Type) ID() Type { return UINT8 }
+func (t *Uint8Type) Name() string { return "uint8" }
+func (t *Uint8Type) BitWidth() int { return 8 }
type Uint16Type struct{}
-func (t *Uint16Type) ID() Type { return UINT16 }
-func (t *Uint16Type) Name() string { return "uint16" }
+func (t *Uint16Type) ID() Type { return UINT16 }
+func (t *Uint16Type) Name() string { return "uint16" }
+func (t *Uint16Type) BitWidth() int { return 16 }
type Uint32Type struct{}
-func (t *Uint32Type) ID() Type { return UINT32 }
-func (t *Uint32Type) Name() string { return "uint32" }
+func (t *Uint32Type) ID() Type { return UINT32 }
+func (t *Uint32Type) Name() string { return "uint32" }
+func (t *Uint32Type) BitWidth() int { return 32 }
type Uint64Type struct{}
-func (t *Uint64Type) ID() Type { return UINT64 }
-func (t *Uint64Type) Name() string { return "uint64" }
+func (t *Uint64Type) ID() Type { return UINT64 }
+func (t *Uint64Type) Name() string { return "uint64" }
+func (t *Uint64Type) BitWidth() int { return 64 }
type Float32Type struct{}
-func (t *Float32Type) ID() Type { return FLOAT32 }
-func (t *Float32Type) Name() string { return "float32" }
+func (t *Float32Type) ID() Type { return FLOAT32 }
+func (t *Float32Type) Name() string { return "float32" }
+func (t *Float32Type) BitWidth() int { return 32 }
type Float64Type struct{}
-func (t *Float64Type) ID() Type { return FLOAT64 }
-func (t *Float64Type) Name() string { return "float64" }
+func (t *Float64Type) ID() Type { return FLOAT64 }
+func (t *Float64Type) Name() string { return "float64" }
+func (t *Float64Type) BitWidth() int { return 64 }
var (
PrimitiveTypes = struct {
diff --git a/go/arrow/datatype_numeric.gen.go.tmpl b/go/arrow/datatype_numeric.gen.go.tmpl
index 582c895..9458964 100644
--- a/go/arrow/datatype_numeric.gen.go.tmpl
+++ b/go/arrow/datatype_numeric.gen.go.tmpl
@@ -21,6 +21,7 @@ type {{.Name}}Type struct {}
func (t *{{.Name}}Type) ID() Type { return {{.Name|upper}} }
func (t *{{.Name}}Type) Name() string { return "{{.Name|lower}}" }
+func (t *{{.Name}}Type) BitWidth() int { return {{.Size}} }
{{end}}
@@ -35,4 +36,4 @@ var (
{{.Name}}: &{{.Name}}Type{},
{{- end}}
}
-)
\ No newline at end of file
+)
diff --git a/go/arrow/datatype_numeric.gen.go.tmpldata b/go/arrow/datatype_numeric.gen.go.tmpldata
index 1f40fd5..415b51b 100644
--- a/go/arrow/datatype_numeric.gen.go.tmpldata
+++ b/go/arrow/datatype_numeric.gen.go.tmpldata
@@ -1,32 +1,52 @@
[
{
- "Name": "Int8"
+ "Name": "Int8",
+ "Type": "int8",
+ "Size": 8
},
{
- "Name": "Int16"
+ "Name": "Int16",
+ "Type": "int16",
+ "Size": 16
},
{
- "Name": "Int32"
+ "Name": "Int32",
+ "Type": "int32",
+ "Size": 32
},
{
- "Name": "Int64"
+ "Name": "Int64",
+ "Type": "int64",
+ "Size": 64
},
{
- "Name": "Uint8"
+ "Name": "Uint8",
+ "Type": "uint8",
+ "Size": 8
},
{
- "Name": "Uint16"
+ "Name": "Uint16",
+ "Type": "uint16",
+ "Size": 16
},
{
- "Name": "Uint32"
+ "Name": "Uint32",
+ "Type": "uint32",
+ "Size": 32
},
{
- "Name": "Uint64"
+ "Name": "Uint64",
+ "Type": "uint64",
+ "Size": 64
},
{
- "Name": "Float32"
+ "Name": "Float32",
+ "Type": "float32",
+ "Size": 32
},
{
- "Name": "Float64"
+ "Name": "Float64",
+ "Type": "float64",
+ "Size": 64
}
-]
\ No newline at end of file
+]
diff --git a/go/arrow/doc.go b/go/arrow/doc.go
index 6ee0c2a..ebd9c8e 100644
--- a/go/arrow/doc.go
+++ b/go/arrow/doc.go
@@ -32,7 +32,7 @@ array is valid (not null). If the array has no null entries, it is possible to o
package arrow
//go:generate go run _tools/tmpl/main.go -i -data=numeric.tmpldata type_traits_numeric.gen.go.tmpl array/numeric.gen.go.tmpl array/numericbuilder.gen.go.tmpl array/bufferbuilder_numeric.gen.go.tmpl
-//go:generate go run _tools/tmpl/main.go -i -data=datatype_numeric.gen.go.tmpldata datatype_numeric.gen.go.tmpl
+//go:generate go run _tools/tmpl/main.go -i -data=datatype_numeric.gen.go.tmpldata datatype_numeric.gen.go.tmpl tensor/numeric.gen.go.tmpl tensor/numeric.gen_test.go.tmpl
// stringer
//go:generate stringer -type=Type
diff --git a/go/arrow/example_test.go b/go/arrow/example_test.go
index ff77c6b..936d8d8 100644
--- a/go/arrow/example_test.go
+++ b/go/arrow/example_test.go
@@ -22,6 +22,7 @@ import (
"github.com/apache/arrow/go/arrow"
"github.com/apache/arrow/go/arrow/array"
"github.com/apache/arrow/go/arrow/memory"
+ "github.com/apache/arrow/go/arrow/tensor"
)
// This example demonstrates how to build an array of int64 values using a builder and Append.
@@ -320,3 +321,89 @@ func Example_float64Slice() {
// array = [1 2 3 -1 4 5]
// slice = [3 -1 4]
}
+
+func Example_float64Tensor2x5() {
+ pool := memory.NewGoAllocator()
+
+ b := array.NewFloat64Builder(pool)
+ defer b.Release()
+
+ raw := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ b.AppendValues(raw, nil)
+
+ arr := b.NewFloat64Array()
+ defer arr.Release()
+
+ f64 := tensor.NewFloat64(arr.Data(), []int64{2, 5}, nil, []string{"x", "y"})
+ defer f64.Release()
+
+ for _, i := range [][]int64{
+ []int64{0, 0},
+ []int64{0, 1},
+ []int64{0, 2},
+ []int64{0, 3},
+ []int64{0, 4},
+ []int64{1, 0},
+ []int64{1, 1},
+ []int64{1, 2},
+ []int64{1, 3},
+ []int64{1, 4},
+ } {
+ fmt.Printf("arr%v = %v\n", i, f64.Value(i))
+ }
+
+ // Output:
+ // arr[0 0] = 1
+ // arr[0 1] = 2
+ // arr[0 2] = 3
+ // arr[0 3] = 4
+ // arr[0 4] = 5
+ // arr[1 0] = 6
+ // arr[1 1] = 7
+ // arr[1 2] = 8
+ // arr[1 3] = 9
+ // arr[1 4] = 10
+}
+
+func Example_float64Tensor2x5ColMajor() {
+ pool := memory.NewGoAllocator()
+
+ b := array.NewFloat64Builder(pool)
+ defer b.Release()
+
+ raw := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ b.AppendValues(raw, nil)
+
+ arr := b.NewFloat64Array()
+ defer arr.Release()
+
+ f64 := tensor.NewFloat64(arr.Data(), []int64{2, 5}, []int64{8, 16}, []string{"x", "y"})
+ defer f64.Release()
+
+ for _, i := range [][]int64{
+ []int64{0, 0},
+ []int64{0, 1},
+ []int64{0, 2},
+ []int64{0, 3},
+ []int64{0, 4},
+ []int64{1, 0},
+ []int64{1, 1},
+ []int64{1, 2},
+ []int64{1, 3},
+ []int64{1, 4},
+ } {
+ fmt.Printf("arr%v = %v\n", i, f64.Value(i))
+ }
+
+ // Output:
+ // arr[0 0] = 1
+ // arr[0 1] = 3
+ // arr[0 2] = 5
+ // arr[0 3] = 7
+ // arr[0 4] = 9
+ // arr[1 0] = 2
+ // arr[1 1] = 4
+ // arr[1 2] = 6
+ // arr[1 3] = 8
+ // arr[1 4] = 10
+}
diff --git a/go/arrow/tensor/numeric.gen.go b/go/arrow/tensor/numeric.gen.go
new file mode 100644
index 0000000..1e9c1e9
--- /dev/null
+++ b/go/arrow/tensor/numeric.gen.go
@@ -0,0 +1,277 @@
+// Code generated by tensor/numeric.gen.go.tmpl. DO NOT EDIT.
+
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tensor
+
+import (
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+)
+
+// Int8 is an n-dim array of int8s.
+type Int8 struct {
+ tensorBase
+ values []int8
+}
+
+// NewInt8 returns a new n-dimensional array of int8s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewInt8(data *array.Data, shape, strides []int64, names []string) *Int8 {
+ tsr := &Int8{tensorBase: *newTensor(arrow.PrimitiveTypes.Int8, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Int8Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Int8) Value(i []int64) int8 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Int8) Int8Values() []int8 { return tsr.values }
+
+// Int16 is an n-dim array of int16s.
+type Int16 struct {
+ tensorBase
+ values []int16
+}
+
+// NewInt16 returns a new n-dimensional array of int16s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewInt16(data *array.Data, shape, strides []int64, names []string) *Int16 {
+ tsr := &Int16{tensorBase: *newTensor(arrow.PrimitiveTypes.Int16, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Int16Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Int16) Value(i []int64) int16 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Int16) Int16Values() []int16 { return tsr.values }
+
+// Int32 is an n-dim array of int32s.
+type Int32 struct {
+ tensorBase
+ values []int32
+}
+
+// NewInt32 returns a new n-dimensional array of int32s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewInt32(data *array.Data, shape, strides []int64, names []string) *Int32 {
+ tsr := &Int32{tensorBase: *newTensor(arrow.PrimitiveTypes.Int32, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Int32Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Int32) Value(i []int64) int32 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Int32) Int32Values() []int32 { return tsr.values }
+
+// Int64 is an n-dim array of int64s.
+type Int64 struct {
+ tensorBase
+ values []int64
+}
+
+// NewInt64 returns a new n-dimensional array of int64s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewInt64(data *array.Data, shape, strides []int64, names []string) *Int64 {
+ tsr := &Int64{tensorBase: *newTensor(arrow.PrimitiveTypes.Int64, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Int64Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Int64) Value(i []int64) int64 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Int64) Int64Values() []int64 { return tsr.values }
+
+// Uint8 is an n-dim array of uint8s.
+type Uint8 struct {
+ tensorBase
+ values []uint8
+}
+
+// NewUint8 returns a new n-dimensional array of uint8s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewUint8(data *array.Data, shape, strides []int64, names []string) *Uint8 {
+ tsr := &Uint8{tensorBase: *newTensor(arrow.PrimitiveTypes.Uint8, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Uint8Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Uint8) Value(i []int64) uint8 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Uint8) Uint8Values() []uint8 { return tsr.values }
+
+// Uint16 is an n-dim array of uint16s.
+type Uint16 struct {
+ tensorBase
+ values []uint16
+}
+
+// NewUint16 returns a new n-dimensional array of uint16s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewUint16(data *array.Data, shape, strides []int64, names []string) *Uint16 {
+ tsr := &Uint16{tensorBase: *newTensor(arrow.PrimitiveTypes.Uint16, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Uint16Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Uint16) Value(i []int64) uint16 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Uint16) Uint16Values() []uint16 { return tsr.values }
+
+// Uint32 is an n-dim array of uint32s.
+type Uint32 struct {
+ tensorBase
+ values []uint32
+}
+
+// NewUint32 returns a new n-dimensional array of uint32s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewUint32(data *array.Data, shape, strides []int64, names []string) *Uint32 {
+ tsr := &Uint32{tensorBase: *newTensor(arrow.PrimitiveTypes.Uint32, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Uint32Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Uint32) Value(i []int64) uint32 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Uint32) Uint32Values() []uint32 { return tsr.values }
+
+// Uint64 is an n-dim array of uint64s.
+type Uint64 struct {
+ tensorBase
+ values []uint64
+}
+
+// NewUint64 returns a new n-dimensional array of uint64s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewUint64(data *array.Data, shape, strides []int64, names []string) *Uint64 {
+ tsr := &Uint64{tensorBase: *newTensor(arrow.PrimitiveTypes.Uint64, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Uint64Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Uint64) Value(i []int64) uint64 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Uint64) Uint64Values() []uint64 { return tsr.values }
+
+// Float32 is an n-dim array of float32s.
+type Float32 struct {
+ tensorBase
+ values []float32
+}
+
+// NewFloat32 returns a new n-dimensional array of float32s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewFloat32(data *array.Data, shape, strides []int64, names []string) *Float32 {
+ tsr := &Float32{tensorBase: *newTensor(arrow.PrimitiveTypes.Float32, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Float32Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Float32) Value(i []int64) float32 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Float32) Float32Values() []float32 { return tsr.values }
+
+// Float64 is an n-dim array of float64s.
+type Float64 struct {
+ tensorBase
+ values []float64
+}
+
+// NewFloat64 returns a new n-dimensional array of float64s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func NewFloat64(data *array.Data, shape, strides []int64, names []string) *Float64 {
+ tsr := &Float64{tensorBase: *newTensor(arrow.PrimitiveTypes.Float64, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.Float64Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *Float64) Value(i []int64) float64 { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *Float64) Float64Values() []float64 { return tsr.values }
+
+var (
+ _ Interface = (*Int8)(nil)
+ _ Interface = (*Int16)(nil)
+ _ Interface = (*Int32)(nil)
+ _ Interface = (*Int64)(nil)
+ _ Interface = (*Uint8)(nil)
+ _ Interface = (*Uint16)(nil)
+ _ Interface = (*Uint32)(nil)
+ _ Interface = (*Uint64)(nil)
+ _ Interface = (*Float32)(nil)
+ _ Interface = (*Float64)(nil)
+)
diff --git a/go/arrow/tensor/numeric.gen.go.tmpl b/go/arrow/tensor/numeric.gen.go.tmpl
new file mode 100644
index 0000000..282cbf2
--- /dev/null
+++ b/go/arrow/tensor/numeric.gen.go.tmpl
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tensor
+
+import (
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+)
+
+{{range .In}}
+
+// {{.Name}} is an n-dim array of {{.Type}}s.
+type {{.Name}} struct {
+ tensorBase
+ values []{{.Type}}
+}
+
+// New{{.Name}} returns a new n-dimensional array of {{.Type}}s.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+func New{{.Name}}(data *array.Data, shape, strides []int64, names []string) *{{.Name}} {
+ tsr := &{{.Name}}{tensorBase:*newTensor(arrow.PrimitiveTypes.{{.Name}}, data, shape, strides, names)}
+ vals := tsr.data.Buffers()[1]
+ if vals != nil {
+ tsr.values = arrow.{{.Name}}Traits.CastFromBytes(vals.Bytes())
+ beg := tsr.data.Offset()
+ end := beg + tsr.data.Len()
+ tsr.values = tsr.values[beg:end]
+ }
+ return tsr
+}
+
+func (tsr *{{.Name}}) Value(i []int64) {{or .Type}} { j := int(tsr.offset(i)); return tsr.values[j] }
+func (tsr *{{.Name}}) {{.Name}}Values() []{{or .Type}} { return tsr.values }
+{{end}}
+
+var (
+{{range .In}}
+ _ Interface = (*{{.Name}})(nil)
+{{- end}}
+)
diff --git a/go/arrow/tensor/numeric.gen_test.go b/go/arrow/tensor/numeric.gen_test.go
new file mode 100644
index 0000000..066f7ca
--- /dev/null
+++ b/go/arrow/tensor/numeric.gen_test.go
@@ -0,0 +1,980 @@
+// Code generated by tensor/numeric.gen_test.go.tmpl. DO NOT EDIT.
+
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tensor_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/memory"
+ "github.com/apache/arrow/go/arrow/tensor"
+)
+
+func TestTensorInt8(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewInt8Builder(mem)
+ defer bld.Release()
+
+ raw := []int8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewInt8Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Int8.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Int8)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Int8Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v int8
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorInt16(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewInt16Builder(mem)
+ defer bld.Release()
+
+ raw := []int16{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewInt16Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Int16.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Int16)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Int16Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v int16
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorInt32(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewInt32Builder(mem)
+ defer bld.Release()
+
+ raw := []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewInt32Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Int32.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Int32)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Int32Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v int32
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorInt64(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewInt64Builder(mem)
+ defer bld.Release()
+
+ raw := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewInt64Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Int64.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Int64)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Int64Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v int64
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorUint8(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewUint8Builder(mem)
+ defer bld.Release()
+
+ raw := []uint8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewUint8Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Uint8.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Uint8)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Uint8Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v uint8
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorUint16(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewUint16Builder(mem)
+ defer bld.Release()
+
+ raw := []uint16{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewUint16Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Uint16.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Uint16)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Uint16Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v uint16
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorUint32(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewUint32Builder(mem)
+ defer bld.Release()
+
+ raw := []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewUint32Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Uint32.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Uint32)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Uint32Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v uint32
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorUint64(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewUint64Builder(mem)
+ defer bld.Release()
+
+ raw := []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewUint64Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Uint64.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Uint64)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Uint64Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v uint64
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorFloat32(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewFloat32Builder(mem)
+ defer bld.Release()
+
+ raw := []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewFloat32Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Float32.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Float32)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Float32Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v float32
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestTensorFloat64(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewFloat64Builder(mem)
+ defer bld.Release()
+
+ raw := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewFloat64Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.Float64.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.Float64)
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5 * bw, 1 * bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.Float64Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v float64
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
diff --git a/go/arrow/tensor/numeric.gen_test.go.tmpl b/go/arrow/tensor/numeric.gen_test.go.tmpl
new file mode 100644
index 0000000..dd512e8
--- /dev/null
+++ b/go/arrow/tensor/numeric.gen_test.go.tmpl
@@ -0,0 +1,126 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tensor_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/memory"
+ "github.com/apache/arrow/go/arrow/tensor"
+)
+
+{{range .In}}
+
+func TestTensor{{.Name}}(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.New{{.Name}}Builder(mem)
+ defer bld.Release()
+
+ raw := []{{.Type}}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.New{{.Name}}Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ bw = int64(arrow.PrimitiveTypes.{{.Name}}.(arrow.FixedWidthDataType).BitWidth()) / 8
+ )
+
+ tsr := tensor.New(arr.Data(), shape, nil, names).(*tensor.{{.Name}})
+ defer tsr.Release()
+
+ tsr.Retain()
+ tsr.Release()
+
+ if got, want := tsr.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := tsr.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.Strides(), []int64{5*bw, 1*bw}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := tsr.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := tsr.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := tsr.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := tsr.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if tsr.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !tsr.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !tsr.IsRowMajor() || tsr.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := tsr.{{.Name}}Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v {{.Type}}
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := tsr.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+{{end}}
diff --git a/go/arrow/tensor/tensor.go b/go/arrow/tensor/tensor.go
new file mode 100644
index 0000000..53d5a45
--- /dev/null
+++ b/go/arrow/tensor/tensor.go
@@ -0,0 +1,239 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package tensor provides types that implement n-dimensional arrays.
+package tensor
+
+import (
+ "fmt"
+ "sync/atomic"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/internal/debug"
+)
+
+// Interface represents an n-dimensional array of numerical data.
+type Interface interface {
+ // Retain increases the reference count by 1.
+ // Retain may be called simultaneously from multiple goroutines.
+ Retain()
+
+ // Release decreases the reference count by 1.
+ // Release may be called simultaneously from multiple goroutines.
+ // When the reference count goes to zero, the memory is freed.
+ Release()
+
+ // Len returns the number of elements in the tensor.
+ Len() int
+
+ // Shape returns the size - in each dimension - of the tensor.
+ Shape() []int64
+
+ // Strides returns the number of bytes to step in each dimension when traversing the tensor.
+ Strides() []int64
+
+ // NumDims returns the number of dimensions of the tensor.
+ NumDims() int
+
+ // DimName returns the name of the i-th dimension.
+ DimName(i int) string
+
+ DataType() arrow.DataType
+ Data() *array.Data
+
+ // IsMutable returns whether the underlying data buffer is mutable.
+ IsMutable() bool
+ IsContiguous() bool
+ IsRowMajor() bool
+ IsColMajor() bool
+}
+
+type tensorBase struct {
+ refCount int64
+ dtype arrow.DataType
+ bw int64 // bytes width
+ data *array.Data
+ shape []int64
+ strides []int64
+ names []string
+}
+
+// Retain increases the reference count by 1.
+// Retain may be called simultaneously from multiple goroutines.
+func (tb *tensorBase) Retain() {
+ atomic.AddInt64(&tb.refCount, 1)
+}
+
+// Release decreases the reference count by 1.
+// Release may be called simultaneously from multiple goroutines.
+// When the reference count goes to zero, the memory is freed.
+func (tb *tensorBase) Release() {
+ debug.Assert(atomic.LoadInt64(&tb.refCount) > 0, "too many releases")
+
+ if atomic.AddInt64(&tb.refCount, -1) == 0 {
+ tb.data.Release()
+ tb.data = nil
+ }
+}
+
+func (tb *tensorBase) Len() int {
+ o := int64(1)
+ for _, v := range tb.shape {
+ o *= v
+ }
+ return int(o)
+}
+
+func (tb *tensorBase) Shape() []int64 { return tb.shape }
+func (tb *tensorBase) Strides() []int64 { return tb.strides }
+func (tb *tensorBase) NumDims() int { return len(tb.shape) }
+func (tb *tensorBase) DimName(i int) string { return tb.names[i] }
+func (tb *tensorBase) DataType() arrow.DataType { return tb.dtype }
+func (tb *tensorBase) Data() *array.Data { return tb.data }
+
+// IsMutable returns whether the underlying data buffer is mutable.
+func (tb *tensorBase) IsMutable() bool { return false } // FIXME(sbinet): implement it at the array.Data level
+
+func (tb *tensorBase) IsContiguous() bool {
+ return tb.IsRowMajor() || tb.IsColMajor()
+}
+
+func (tb *tensorBase) IsRowMajor() bool {
+ strides := rowMajorStrides(tb.dtype, tb.shape)
+ return equalInt64s(strides, tb.strides)
+}
+
+func (tb *tensorBase) IsColMajor() bool {
+ strides := colMajorStrides(tb.dtype, tb.shape)
+ return equalInt64s(strides, tb.strides)
+}
+
+func (tb *tensorBase) offset(index []int64) int64 {
+ var offset int64
+ for i, v := range index {
+ offset += v * tb.strides[i]
+ }
+ return offset / tb.bw
+}
+
+// New returns a new n-dim array from the provided backing data and the shape and strides.
+// If strides is nil, row-major strides will be inferred.
+// If names is nil, a slice of empty strings will be created.
+//
+// New panics if the backing data is not a numerical type.
+func New(data *array.Data, shape, strides []int64, names []string) Interface {
+ dt := data.DataType()
+ switch dt.ID() {
+ case arrow.INT8:
+ return NewInt8(data, shape, strides, names)
+ case arrow.INT16:
+ return NewInt16(data, shape, strides, names)
+ case arrow.INT32:
+ return NewInt32(data, shape, strides, names)
+ case arrow.INT64:
+ return NewInt64(data, shape, strides, names)
+ case arrow.UINT8:
+ return NewUint8(data, shape, strides, names)
+ case arrow.UINT16:
+ return NewUint16(data, shape, strides, names)
+ case arrow.UINT32:
+ return NewUint32(data, shape, strides, names)
+ case arrow.UINT64:
+ return NewUint64(data, shape, strides, names)
+ case arrow.FLOAT32:
+ return NewFloat32(data, shape, strides, names)
+ case arrow.FLOAT64:
+ return NewFloat64(data, shape, strides, names)
+ default:
+ panic(fmt.Errorf("arrow/tensor: invalid data type %s", dt.Name()))
+ }
+}
+
+func newTensor(dtype arrow.DataType, data *array.Data, shape, strides []int64, names []string) *tensorBase {
+ tb := tensorBase{
+ refCount: 1,
+ dtype: dtype,
+ bw: int64(dtype.(arrow.FixedWidthDataType).BitWidth()) / 8,
+ data: data,
+ shape: shape,
+ strides: strides,
+ names: names,
+ }
+ tb.data.Retain()
+
+ if len(tb.shape) > 0 && len(tb.strides) == 0 {
+ tb.strides = rowMajorStrides(dtype, shape)
+ }
+ return &tb
+}
+
+func rowMajorStrides(dtype arrow.DataType, shape []int64) []int64 {
+ dt := dtype.(arrow.FixedWidthDataType)
+ rem := int64(dt.BitWidth() / 8)
+ for _, v := range shape {
+ rem *= v
+ }
+
+ if rem == 0 {
+ strides := make([]int64, len(shape))
+ rem := int64(dt.BitWidth() / 8)
+ for i := range strides {
+ strides[i] = rem
+ }
+ return strides
+ }
+
+ var strides []int64
+ for _, v := range shape {
+ rem /= v
+ strides = append(strides, rem)
+ }
+ return strides
+}
+
+func colMajorStrides(dtype arrow.DataType, shape []int64) []int64 {
+ dt := dtype.(arrow.FixedWidthDataType)
+ total := int64(dt.BitWidth() / 8)
+ for _, v := range shape {
+ if v == 0 {
+ strides := make([]int64, len(shape))
+ for i := range strides {
+ strides[i] = total
+ }
+ return strides
+ }
+ }
+
+ var strides []int64
+ for _, v := range shape {
+ strides = append(strides, total)
+ total *= v
+ }
+ return strides
+}
+
+func equalInt64s(a, b []int64) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/go/arrow/tensor/tensor_test.go b/go/arrow/tensor/tensor_test.go
new file mode 100644
index 0000000..cb2631c
--- /dev/null
+++ b/go/arrow/tensor/tensor_test.go
@@ -0,0 +1,162 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tensor_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/apache/arrow/go/arrow"
+ "github.com/apache/arrow/go/arrow/array"
+ "github.com/apache/arrow/go/arrow/memory"
+ "github.com/apache/arrow/go/arrow/tensor"
+)
+
+func TestTensor(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewFloat64Builder(mem)
+ defer bld.Release()
+
+ raw := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewFloat64Array()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ )
+
+ f64 := tensor.New(arr.Data(), shape, nil, names).(*tensor.Float64)
+ defer f64.Release()
+
+ f64.Retain()
+ f64.Release()
+
+ if got, want := f64.Len(), 10; got != want {
+ t.Fatalf("invalid length: got=%d, want=%d", got, want)
+ }
+
+ if got, want := f64.Shape(), shape; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid shape: got=%v, want=%v", got, want)
+ }
+
+ if got, want := f64.Strides(), []int64{40, 8}; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid strides: got=%v, want=%v", got, want)
+ }
+
+ if got, want := f64.NumDims(), 2; got != want {
+ t.Fatalf("invalid dims: got=%d, want=%d", got, want)
+ }
+
+ for i, name := range names {
+ if got, want := f64.DimName(i), name; got != want {
+ t.Fatalf("invalid dim-name[%d]: got=%q, want=%q", i, got, want)
+ }
+ }
+
+ if got, want := f64.DataType(), arr.DataType(); got != want {
+ t.Fatalf("invalid data-type: got=%q, want=%q", got.Name(), want.Name())
+ }
+
+ if got, want := f64.Data(), arr.Data(); got != want {
+ t.Fatalf("invalid data: got=%v, want=%v", got, want)
+ }
+
+ if f64.IsMutable() {
+ t.Fatalf("should not be mutable")
+ }
+
+ if !f64.IsContiguous() {
+ t.Fatalf("should be contiguous")
+ }
+
+ if !f64.IsRowMajor() || f64.IsColMajor() {
+ t.Fatalf("should be row-major")
+ }
+
+ if got, want := f64.Float64Values(), raw; !reflect.DeepEqual(got, want) {
+ t.Fatalf("invalid backing array: got=%v, want=%v", got, want)
+ }
+
+ for _, tc := range []struct {
+ i []int64
+ v float64
+ }{
+ {i: []int64{0, 0}, v: 1},
+ {i: []int64{0, 1}, v: 2},
+ {i: []int64{0, 2}, v: 3},
+ {i: []int64{0, 3}, v: 4},
+ {i: []int64{0, 4}, v: 5},
+ {i: []int64{1, 0}, v: 6},
+ {i: []int64{1, 1}, v: 7},
+ {i: []int64{1, 2}, v: 8},
+ {i: []int64{1, 3}, v: 9},
+ {i: []int64{1, 4}, v: 10},
+ } {
+ t.Run(fmt.Sprintf("%v", tc.i), func(t *testing.T) {
+ got := f64.Value(tc.i)
+ if got != tc.v {
+ t.Fatalf("arr[%v]: got=%v, want=%v", tc.i, got, tc.v)
+ }
+ })
+ }
+}
+
+func TestInvalidTensor(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ bld := array.NewBinaryBuilder(mem, arrow.BinaryTypes.Binary)
+ defer bld.Release()
+
+ raw := [][]byte{{1}, {2, 2}, {3, 3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}}
+ bld.AppendValues(raw, nil)
+
+ arr := bld.NewBinaryArray()
+ defer arr.Release()
+
+ var (
+ shape = []int64{2, 5}
+ names = []string{"x", "y"}
+ )
+
+ t.Run("invalid-binary", func(t *testing.T) {
+ want := fmt.Errorf("arrow/tensor: invalid data type binary")
+ defer func() {
+ e := recover()
+ if e == nil {
+ t.Fatalf("expected an error: %v", want)
+ }
+ switch err := e.(type) {
+ case error:
+ if !reflect.DeepEqual(err, want) {
+ t.Fatalf("invalid error: got=%v (%T), want=%v", err, err, want)
+ }
+ default:
+ t.Fatalf("invalid error: got=%v (%T), want=%v", err, err, want)
+ }
+ }()
+ tsr := tensor.New(arr.Data(), shape, nil, names)
+ defer tsr.Release()
+ })
+
+}