Skip to content

Commit

Permalink
feat(arrow/compute): Implement kernel for "not" function (#178)
Browse files Browse the repository at this point in the history
Adding implementation and tests for a "not" function to the compute
package.
  • Loading branch information
zeroshade authored Oct 28, 2024
1 parent 5a8e388 commit 721a61b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 3 deletions.
4 changes: 2 additions & 2 deletions arrow/compute/exprs/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func init() {
}
}

for _, fn := range []string{"and", "or"} {
for _, fn := range []string{"and", "or", "not"} {
err := DefaultExtensionIDRegistry.AddSubstraitScalarToArrow(
extensions.ID{URI: SubstraitBooleanFuncsURI, Name: fn},
simpleMapSubstraitToArrowFunc)
Expand All @@ -120,7 +120,7 @@ func init() {
}
}

for _, fn := range []string{"and_kleene", "or_kleene"} {
for _, fn := range []string{"and_kleene", "or_kleene", "not"} {
err := DefaultExtensionIDRegistry.AddArrowToSubstrait(fn,
simpleMapArrowToSubstraitFunc(SubstraitBooleanFuncsURI))
if err != nil {
Expand Down
15 changes: 14 additions & 1 deletion arrow/compute/internal/kernels/scalar_boolean.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (

type computeWordFN func(leftTrue, leftFalse, rightTrue, rightFalse uint64) (outValid, outData uint64)

func computeKleene(computeWord computeWordFN, ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
func computeKleene(computeWord computeWordFN, _ *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
var (
inBMs = [4]bitutil.Bitmap{
{Data: left.Buffers[0].Buf, Offset: left.Offset, Len: left.Len},
Expand Down Expand Up @@ -332,3 +332,16 @@ func (KleeneAndNotOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scal
func (KleeneAndNotOpKernel) CallScalarRight(ctx *exec.KernelCtx, left *exec.ArraySpan, right scalar.Scalar, out *exec.ExecResult) error {
return (KleeneAndOpKernel{}).CallScalarRight(ctx, left, invertScalar(right), out)
}

func NotExecKernel(ctx *exec.KernelCtx, batch *exec.ExecSpan, out *exec.ExecResult) error {
bitutil.InvertBitmap(batch.Values[0].Array.Buffers[1].Buf, int(batch.Values[0].Array.Offset),
int(batch.Values[0].Array.Len), out.Buffers[1].Buf, int(out.Offset))

out.Buffers[0] = batch.Values[0].Array.Buffers[0]
if out.Buffers[0].SelfAlloc {
out.Buffers[0].SelfAlloc = false
}
out.Nulls = batch.Values[0].Array.Nulls

return nil
}
7 changes: 7 additions & 0 deletions arrow/compute/scalar_bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ var (
For a different null behavior, see function "and".`,
ArgNames: []string{"x", "y"},
}
notDoc = FunctionDoc{
Summary: "Logical 'not' boolean values",
Description: "Negates the input boolean value",
ArgNames: []string{"x"},
}
)

func makeFunction(reg FunctionRegistry, name string, arity int, ex exec.ArrayKernelExec, doc FunctionDoc, nulls exec.NullHandling) {
Expand Down Expand Up @@ -130,4 +135,6 @@ func RegisterScalarBoolean(reg FunctionRegistry) {
andNotKleeneDoc, exec.NullComputedPrealloc)
makeFunction(reg, "or_kleene", 2, kernels.SimpleBinary[kernels.KleeneOrOpKernel],
orKleeneDoc, exec.NullComputedPrealloc)
makeFunction(reg, "not", 1, kernels.NotExecKernel, notDoc,
exec.NullComputedNoPrealloc)
}
28 changes: 28 additions & 0 deletions arrow/compute/scalar_bool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,31 @@ func TestBooleanKleeneKernels(t *testing.T) {
})
}
}

func TestBooleanNot(t *testing.T) {
tests := []struct {
inputJSON, expectedJSON string
}{
{"[true, true, false, false]", "[false, false, true, true]"},
{"[null, true, null, false]", "[null, false, null, true]"},
{"[null, null, null, null]", "[null, null, null, null]"},
}

for _, tt := range tests {
mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
defer mem.AssertSize(t, 0)

input, _, err := array.FromJSON(mem, arrow.FixedWidthTypes.Boolean,
strings.NewReader(tt.inputJSON))
require.NoError(t, err)
defer input.Release()

expected, _, err := array.FromJSON(mem, arrow.FixedWidthTypes.Boolean,
strings.NewReader(tt.expectedJSON))
require.NoError(t, err)
defer expected.Release()

checkScalarUnary(t, "not", compute.NewDatumWithoutOwning(input),
compute.NewDatumWithoutOwning(expected), nil)
}
}

0 comments on commit 721a61b

Please sign in to comment.