You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ko...@apache.org on 2023/06/13 00:18:32 UTC

[arrow] branch main updated: GH-35984: [MATLAB] Add null support to all numeric array classes (#36039)

This is an automated email from the ASF dual-hosted git repository.

kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new c13275e1e1 GH-35984: [MATLAB] Add null support to all numeric array classes (#36039)
c13275e1e1 is described below

commit c13275e1e16d2db1a076398e4061a38243069c09
Author: sgilmore10 <74...@users.noreply.github.com>
AuthorDate: Mon Jun 12 20:18:24 2023 -0400

    GH-35984: [MATLAB] Add null support to all numeric array classes (#36039)
    
    ### Rationale for this change
    
    We initially only enabled null support for `arrow.array.Float64Array` via the `InferNulls` and `Valid` name-value pairs. This pull request adds null-value support to the rest of the numeric array types.
    
    ### What changes are included in this PR?
    
    1. All numeric array classes accept the `InferNulls` and `Valid` name-value pairs.
    2. `arrow.array.Float32Array` treats `NaN` as `null` by default if `InferNulls=true` and `Valid` is not supplied.
    3. To reduce code duplication, we added an abstract class called `arrow.array.NumericArray` that all numeric array classes inherit form.
    
    Here's an example of creating an `Int32Array` with `null` values:
    
    ```MATLAB
    >> matlabArray = int32([1 2 3 4 5]);
    >> arrowArray = arrow.array.Int32Array(matlabArray, Valid=[1 4 5])
    arrowArray =
    
    [
      1,
      null,
      null,
      4,
      5
    ]
    
    ```
    
    ### Are these changes tested?
    
    1. Added two unit tests to `hNumericArray.m` called `LogicalValidNVPair` and `NumericValidNVPair` which test the null support integration of all numeric types.
    2. Added unit tests to `tFloat32Array.m` to verify `NaN `is treated as a null value by default.
    
    ### Are there any user-facing changes?
    
    Yes, users can now create numeric arrays of any type with null values.
    
    ### Notes
    
    Thanks to @ kevingurney for all the help!
    
    * Closes: #35984
    
    Authored-by: Sarah Gilmore <sg...@mathworks.com>
    Signed-off-by: Sutou Kouhei <ko...@clear-code.com>
---
 matlab/src/matlab/+arrow/+array/Float32Array.m     | 21 +++---
 matlab/src/matlab/+arrow/+array/Float64Array.m     | 31 +++------
 matlab/src/matlab/+arrow/+array/Int16Array.m       | 23 +++----
 matlab/src/matlab/+arrow/+array/Int32Array.m       | 22 +++---
 matlab/src/matlab/+arrow/+array/Int64Array.m       | 20 ++----
 matlab/src/matlab/+arrow/+array/Int8Array.m        | 21 ++----
 .../+array/{Float64Array.m => NumericArray.m}      | 36 +++++-----
 matlab/src/matlab/+arrow/+array/UInt16Array.m      | 22 +++---
 matlab/src/matlab/+arrow/+array/UInt32Array.m      | 22 +++---
 matlab/src/matlab/+arrow/+array/UInt64Array.m      | 23 +++----
 matlab/src/matlab/+arrow/+array/UInt8Array.m       | 24 +++----
 matlab/test/arrow/array/hNumericArray.m            | 31 ++++++++-
 matlab/test/arrow/array/tFloat32Array.m            | 78 ++++++++++++++++++++++
 matlab/test/arrow/array/tFloat64Array.m            |  1 +
 matlab/test/arrow/array/tInt32Array.m              |  4 +-
 matlab/test/arrow/array/tInt64Array.m              |  2 +-
 matlab/test/arrow/array/tInt8Array.m               |  1 +
 matlab/test/arrow/array/tUInt16Array.m             |  3 +-
 matlab/test/arrow/array/tUInt32Array.m             |  7 +-
 matlab/test/arrow/array/tUInt64Array.m             |  6 +-
 matlab/test/arrow/array/tUInt8Array.m              |  5 +-
 21 files changed, 225 insertions(+), 178 deletions(-)

diff --git a/matlab/src/matlab/+arrow/+array/Float32Array.m b/matlab/src/matlab/+arrow/+array/Float32Array.m
index f35be565e4..c6be563d86 100644
--- a/matlab/src/matlab/+arrow/+array/Float32Array.m
+++ b/matlab/src/matlab/+arrow/+array/Float32Array.m
@@ -12,27 +12,22 @@
 % 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.
-classdef Float32Array < arrow.array.Array
+
+classdef Float32Array < arrow.array.NumericArray
 % arrow.array.Float32Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = single([])
+    properties (Access=protected)
+        NullSubstitutionValue = single(NaN);
     end
 
     methods
-        function obj = Float32Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            arrow.args.validateTypeAndShape(data, "single");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.Float32Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = Float32Array(data, varargin)
+            obj@arrow.array.NumericArray(data, "single", ...
+                "arrow.array.proxy.Float32Array", varargin{:});
         end
 
         function data = single(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
 end
diff --git a/matlab/src/matlab/+arrow/+array/Float64Array.m b/matlab/src/matlab/+arrow/+array/Float64Array.m
index 67c29145e7..ff43ebc053 100644
--- a/matlab/src/matlab/+arrow/+array/Float64Array.m
+++ b/matlab/src/matlab/+arrow/+array/Float64Array.m
@@ -1,4 +1,4 @@
- % Licensed to the Apache Software Foundation (ASF) under one or more
+% 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
@@ -12,37 +12,22 @@
 % 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.
-classdef Float64Array < arrow.array.Array
+
+classdef Float64Array < arrow.array.NumericArray
 % arrow.array.Float64Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray
-        NullSubstitionValue = NaN;
+    properties (Access=protected)
+        NullSubstitutionValue = NaN;
     end
 
     methods
-        function obj = Float64Array(data, opts, nullOpts)
-            arguments
-                data
-                opts.DeepCopy(1, 1) logical = false
-                nullOpts.InferNulls(1, 1) logical = true
-                nullOpts.Valid
-            end
-            arrow.args.validateTypeAndShape(data, "double");
-            validElements = arrow.args.parseValidElements(data, nullOpts);
-            obj@arrow.array.Array("Name", "arrow.array.proxy.Float64Array", "ConstructorArguments", {data, opts.DeepCopy, validElements});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = Float64Array(data, varargin)
+            obj@arrow.array.NumericArray(data, "double", ...
+                "arrow.array.proxy.Float64Array", varargin{:});
         end
 
         function data = double(obj)
             data = obj.toMATLAB();
         end
-
-        function matlabArray = toMATLAB(obj)
-            matlabArray = obj.Proxy.toMATLAB();
-            matlabArray(~obj.Valid) = obj.NullSubstitionValue;
-        end
     end
 end
-
diff --git a/matlab/src/matlab/+arrow/+array/Int16Array.m b/matlab/src/matlab/+arrow/+array/Int16Array.m
index 6daa719adf..533f0c9ef5 100644
--- a/matlab/src/matlab/+arrow/+array/Int16Array.m
+++ b/matlab/src/matlab/+arrow/+array/Int16Array.m
@@ -12,29 +12,22 @@
 % 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.
-    
-classdef Int16Array < arrow.array.Array
+
+classdef Int16Array < arrow.array.NumericArray
 % arrow.array.Int16Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = int16([])
+    properties (Access=protected)
+        NullSubstitutionValue = int16(0)
     end
 
     methods
-        function obj = Int16Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-
-            arrow.args.validateTypeAndShape(data, "int16");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.Int16Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = Int16Array(data, varargin)
+            obj@arrow.array.NumericArray(data, "int16", ...
+                "arrow.array.proxy.Int16Array", varargin{:});
         end
 
         function data = int16(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
 end
diff --git a/matlab/src/matlab/+arrow/+array/Int32Array.m b/matlab/src/matlab/+arrow/+array/Int32Array.m
index 58ecefdba9..0f977fb90f 100644
--- a/matlab/src/matlab/+arrow/+array/Int32Array.m
+++ b/matlab/src/matlab/+arrow/+array/Int32Array.m
@@ -13,27 +13,21 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-classdef Int32Array < arrow.array.Array
-    % arrow.array.Int32Array
+classdef Int32Array < arrow.array.NumericArray
+% arrow.array.Int32Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = int32([])
+    properties (Access=protected)
+        NullSubstitutionValue = int32(0)
     end
 
     methods
-        function obj = Int32Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            arrow.args.validateTypeAndShape(data, "int32");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.Int32Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = Int32Array(data, varargin)
+              obj@arrow.array.NumericArray(data, "int32", ...
+                "arrow.array.proxy.Int32Array", varargin{:});
         end
 
         function data = int32(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
 end
diff --git a/matlab/src/matlab/+arrow/+array/Int64Array.m b/matlab/src/matlab/+arrow/+array/Int64Array.m
index 17360f17d4..94cad56519 100644
--- a/matlab/src/matlab/+arrow/+array/Int64Array.m
+++ b/matlab/src/matlab/+arrow/+array/Int64Array.m
@@ -13,27 +13,21 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-classdef Int64Array < arrow.array.Array
+classdef Int64Array < arrow.array.NumericArray
 % arrow.array.Int64Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = int64([])
+    properties (Access=protected)
+        NullSubstitutionValue = int64(0);
     end
 
     methods
-        function obj = Int64Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            arrow.args.validateTypeAndShape(data, "int64");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.Int64Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = Int64Array(data, varargin)
+          obj@arrow.array.NumericArray(data, "int64", ...
+                "arrow.array.proxy.Int64Array", varargin{:});
         end
 
         function data = int64(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
 end
diff --git a/matlab/src/matlab/+arrow/+array/Int8Array.m b/matlab/src/matlab/+arrow/+array/Int8Array.m
index 99d3347c0f..83a14caa27 100644
--- a/matlab/src/matlab/+arrow/+array/Int8Array.m
+++ b/matlab/src/matlab/+arrow/+array/Int8Array.m
@@ -13,28 +13,21 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-classdef Int8Array < arrow.array.Array
+classdef Int8Array < arrow.array.NumericArray
 % arrow.array.Int8Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = int8([])
+    properties (Access=protected)
+        NullSubstitutionValue = int8(0);
     end
 
     methods
-        function obj = Int8Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            
-            arrow.args.validateTypeAndShape(data, "int8");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.Int8Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = Int8Array(data, varargin)
+             obj@arrow.array.NumericArray(data, "int8", ...
+                "arrow.array.proxy.Int8Array", varargin{:});
         end
 
         function data = int8(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
 end
diff --git a/matlab/src/matlab/+arrow/+array/Float64Array.m b/matlab/src/matlab/+arrow/+array/NumericArray.m
similarity index 59%
copy from matlab/src/matlab/+arrow/+array/Float64Array.m
copy to matlab/src/matlab/+arrow/+array/NumericArray.m
index 67c29145e7..86fae54ae1 100644
--- a/matlab/src/matlab/+arrow/+array/Float64Array.m
+++ b/matlab/src/matlab/+arrow/+array/NumericArray.m
@@ -1,4 +1,4 @@
- % Licensed to the Apache Software Foundation (ASF) under one or more
+% 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
@@ -12,36 +12,40 @@
 % 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.
-classdef Float64Array < arrow.array.Array
-% arrow.array.Float64Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray
-        NullSubstitionValue = NaN;
+classdef NumericArray < arrow.array.Array
+    % arrow.array.NumericArray
+    
+    
+    properties (Hidden, SetAccess=protected)
+        MatlabArray = []
+    end
+
+    properties(Abstract, Access=protected)
+        NullSubstitutionValue;
     end
 
     methods
-        function obj = Float64Array(data, opts, nullOpts)
+        function obj = NumericArray(data, type, proxyName, opts, nullOpts)
             arguments
                 data
+                type(1, 1) string
+                proxyName(1, 1) string
                 opts.DeepCopy(1, 1) logical = false
                 nullOpts.InferNulls(1, 1) logical = true
                 nullOpts.Valid
             end
-            arrow.args.validateTypeAndShape(data, "double");
+            arrow.args.validateTypeAndShape(data, type);
             validElements = arrow.args.parseValidElements(data, nullOpts);
-            obj@arrow.array.Array("Name", "arrow.array.proxy.Float64Array", "ConstructorArguments", {data, opts.DeepCopy, validElements});
+            obj@arrow.array.Array("Name", proxyName, "ConstructorArguments", {data, opts.DeepCopy, validElements});
+            obj.MatlabArray = cast(obj.MatlabArray, type);
             % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+            if ~opts.DeepCopy, obj.MatlabArray = data; end
         end
-
-        function data = double(obj)
-            data = obj.toMATLAB();
-        end
-
+        
         function matlabArray = toMATLAB(obj)
             matlabArray = obj.Proxy.toMATLAB();
-            matlabArray(~obj.Valid) = obj.NullSubstitionValue;
+            matlabArray(~obj.Valid) = obj.NullSubstitutionValue;
         end
     end
 end
diff --git a/matlab/src/matlab/+arrow/+array/UInt16Array.m b/matlab/src/matlab/+arrow/+array/UInt16Array.m
index 6b3839c022..4862ca20b9 100644
--- a/matlab/src/matlab/+arrow/+array/UInt16Array.m
+++ b/matlab/src/matlab/+arrow/+array/UInt16Array.m
@@ -13,27 +13,21 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-classdef UInt16Array < arrow.array.Array
+classdef UInt16Array < arrow.array.NumericArray
 % arrow.array.UInt16Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = uint16([])
+    properties (Access=protected)
+        NullSubstitutionValue = uint16(0)
     end
 
     methods
-        function obj = UInt16Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            arrow.args.validateTypeAndShape(data, "uint16");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.UInt16Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = UInt16Array(data, varargin)
+            obj@arrow.array.NumericArray(data, "uint16", ...
+                "arrow.array.proxy.UInt16Array", varargin{:});
         end
 
         function data = uint16(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/src/matlab/+arrow/+array/UInt32Array.m b/matlab/src/matlab/+arrow/+array/UInt32Array.m
index 884dc1f5ed..782b001099 100644
--- a/matlab/src/matlab/+arrow/+array/UInt32Array.m
+++ b/matlab/src/matlab/+arrow/+array/UInt32Array.m
@@ -13,27 +13,21 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-classdef UInt32Array < arrow.array.Array
+classdef UInt32Array < arrow.array.NumericArray
 % arrow.array.UInt32Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = uint32([])
+    properties (Access=protected)
+        NullSubstitutionValue = uint32(0)
     end
 
     methods
-        function obj = UInt32Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            arrow.args.validateTypeAndShape(data, "uint32");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.UInt32Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = UInt32Array(data, varargin)
+            obj@arrow.array.NumericArray(data, "uint32", ...
+                "arrow.array.proxy.UInt32Array", varargin{:});
         end
 
         function data = uint32(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/src/matlab/+arrow/+array/UInt64Array.m b/matlab/src/matlab/+arrow/+array/UInt64Array.m
index c8abac34dd..f323a613f4 100644
--- a/matlab/src/matlab/+arrow/+array/UInt64Array.m
+++ b/matlab/src/matlab/+arrow/+array/UInt64Array.m
@@ -12,28 +12,23 @@
 % 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.
+<<<<<<< HEAD
 
-classdef UInt64Array < arrow.array.Array
+classdef UInt64Array < arrow.array.NumericArray
 % arrow.array.UInt64Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = uint64([])
+    properties (Access=protected)
+        NullSubstitutionValue = uint64(0)
     end
 
     methods
-        function obj = UInt64Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            arrow.args.validateTypeAndShape(data, "uint64");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.UInt64Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = UInt64Array(data, varargin)
+            obj@arrow.array.NumericArray(data, "uint64", ...
+                "arrow.array.proxy.UInt64Array", varargin{:});
         end
 
         function data = uint64(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/src/matlab/+arrow/+array/UInt8Array.m b/matlab/src/matlab/+arrow/+array/UInt8Array.m
index 1c652b209b..8bad2401bd 100644
--- a/matlab/src/matlab/+arrow/+array/UInt8Array.m
+++ b/matlab/src/matlab/+arrow/+array/UInt8Array.m
@@ -12,28 +12,22 @@
 % 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.
-    
-classdef UInt8Array < arrow.array.Array
+
+classdef UInt8Array < arrow.array.NumericArray
 % arrow.array.UInt8Array
 
-    properties (Hidden, SetAccess=private)
-        MatlabArray = uint8([])
+    properties (Access=protected)
+        NullSubstitutionValue = uint8(0)
     end
 
     methods
-        function obj = UInt8Array(data, opts)
-            arguments
-                data
-                opts.DeepCopy = false
-            end
-            arrow.args.validateTypeAndShape(data, "uint8");
-            obj@arrow.array.Array("Name", "arrow.array.proxy.UInt8Array", "ConstructorArguments", {data, opts.DeepCopy});
-            % Store a reference to the array if not doing a deep copy
-            if (~opts.DeepCopy), obj.MatlabArray = data; end
+        function obj = UInt8Array(data, varargin)
+            obj@arrow.array.NumericArray(data, "uint8", ...
+                "arrow.array.proxy.UInt8Array", varargin{:});
         end
 
         function data = uint8(obj)
-            data = obj.Proxy.toMATLAB();
+            data = obj.toMATLAB();
         end
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/test/arrow/array/hNumericArray.m b/matlab/test/arrow/array/hNumericArray.m
index 7d3696a8c7..42c839a0c8 100644
--- a/matlab/test/arrow/array/hNumericArray.m
+++ b/matlab/test/arrow/array/hNumericArray.m
@@ -16,13 +16,14 @@
 classdef hNumericArray < matlab.unittest.TestCase
 % Test class containing shared tests for numeric arrays.
 
-      properties (Abstract)
+    properties (Abstract)
         ArrowArrayClassName(1, 1) string
         ArrowArrayConstructor
         MatlabArrayFcn
         MatlabConversionFcn
         MaxValue (1, 1)
         MinValue (1, 1)
+        NullSubstitutionValue(1, 1)
     end
 
     properties (TestParameter)
@@ -130,5 +131,31 @@ classdef hNumericArray < matlab.unittest.TestCase
             fcn = @() tc.ArrowArrayConstructor(data, DeepCopy=MakeDeepCopy);
             tc.verifyError(fcn, "MATLAB:expected2D");
         end
+
+        function LogicalValidNVPair(tc, MakeDeepCopy)
+            % Verify the expected elements are treated as null when Valid
+            % is provided as a logical array
+            data = tc.MatlabArrayFcn([1 2 3 4]);
+            arrowArray = tc.ArrowArrayConstructor(data, Valid=[false true true false], DeepCopy=MakeDeepCopy);
+        
+            expectedData = data';
+            expectedData([1 4]) = tc.NullSubstitutionValue;
+            tc.verifyEqual(tc.MatlabConversionFcn(arrowArray), expectedData);
+            tc.verifyEqual(toMATLAB(arrowArray), expectedData);
+            tc.verifyEqual(arrowArray.Valid, [false; true; true; false]);
+        end
+
+        function NumericValidNVPair(tc, MakeDeepCopy)
+            % Verify the expected elements are treated as null when Valid
+            % is provided as a array of indices
+            data = tc.MatlabArrayFcn([1 2 3 4]);
+            arrowArray = tc.ArrowArrayConstructor(data, Valid=[2 4], DeepCopy=MakeDeepCopy);
+        
+            expectedData = data';
+            expectedData([1 3]) = tc.NullSubstitutionValue;
+            tc.verifyEqual(tc.MatlabConversionFcn(arrowArray), expectedData);
+            tc.verifyEqual(toMATLAB(arrowArray), expectedData);
+            tc.verifyEqual(arrowArray.Valid, [false; true; false; true]);
+        end
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/test/arrow/array/tFloat32Array.m b/matlab/test/arrow/array/tFloat32Array.m
index c1570db0a5..8e21adb0a1 100644
--- a/matlab/test/arrow/array/tFloat32Array.m
+++ b/matlab/test/arrow/array/tFloat32Array.m
@@ -23,6 +23,7 @@ classdef tFloat32Array < hNumericArray
         MatlabArrayFcn = @single % single function
         MaxValue = realmax("single")
         MinValue = realmin("single")
+        NullSubstitutionValue = single(NaN)
     end
 
     methods(Test)
@@ -31,5 +32,82 @@ classdef tFloat32Array < hNumericArray
             data = single(A1);
             testCase.verifyEqual(data, single([Inf -Inf]'));
         end
+
+        function ValidBasic(testCase, MakeDeepCopy)
+            % Create a MATLAB array with one null value (i.e. one NaN).
+            % Verify NaN is considered a null value by default.
+            matlabArray = single([1, NaN, 3]');
+            arrowArray = arrow.array.Float32Array(matlabArray, DeepCopy=MakeDeepCopy);
+            expectedValid = [true, false, true]';
+            testCase.verifyEqual(arrowArray.Valid, expectedValid);
+        end
+
+        function InferNulls(testCase, MakeDeepCopy)
+            matlabArray = single([1, NaN, 3]);
+
+            % Verify NaN is treated as a null value when InferNulls=true.
+            arrowArray1 = arrow.array.Float32Array(matlabArray, InferNulls=true, DeepCopy=MakeDeepCopy);
+            expectedValid1 = [true false true]';
+            testCase.verifyEqual(arrowArray1.Valid, expectedValid1);
+            testCase.verifyEqual(toMATLAB(arrowArray1), matlabArray');
+
+            % Verify NaN is not treated as a null value when InferNulls=false.
+            arrowArray2 = arrow.array.Float32Array(matlabArray, InferNulls=false, DeepCopy=MakeDeepCopy);
+            expectedValid2 = [true true true]';
+            testCase.verifyEqual(arrowArray2.Valid, expectedValid2);
+            testCase.verifyEqual(toMATLAB(arrowArray2), matlabArray');
+        end
+
+        function ValidNoNulls(testCase, MakeDeepCopy)
+            % Create a MATLAB array with no null values (i.e. no NaNs).
+            matlabArray = single([1, 2, 3]');
+            arrowArray = arrow.array.Float32Array(matlabArray, DeepCopy=MakeDeepCopy);
+            expectedValid = [true, true, true]';
+            testCase.verifyEqual(arrowArray.Valid, expectedValid);
+        end
+
+        function ValidAllNulls(testCase, MakeDeepCopy)
+            % Create a MATLAB array with all null values (i.e. all NaNs).
+            matlabArray = single([NaN, NaN, NaN]');
+            arrowArray = arrow.array.Float32Array(matlabArray, DeepCopy=MakeDeepCopy);
+            expectedValid = [false, false, false]';
+            testCase.verifyEqual(arrowArray.Valid, expectedValid);
+        end
+
+        function EmptyArrayValidBitmap(testCase, MakeDeepCopy)
+            % Create an empty 0x0 MATLAB array.
+            matlabArray = single.empty(0, 0);
+            arrowArray = arrow.array.Float32Array(matlabArray, DeepCopy=MakeDeepCopy);
+            expectedValid = logical.empty(0, 1);
+            testCase.verifyEqual(arrowArray.Valid, expectedValid);
+
+            % Create an empty 0x1 MATLAB array.
+            matlabArray = single.empty(0, 1);
+            arrowArray = arrow.array.Float32Array(matlabArray, DeepCopy=MakeDeepCopy);
+            testCase.verifyEqual(arrowArray.Valid, expectedValid);
+
+            % Create an empty 1x0 MATLAB array.
+            matlabArray = single.empty(1, 0);
+            arrowArray = arrow.array.Float32Array(matlabArray, DeepCopy=MakeDeepCopy);
+            testCase.verifyEqual(arrowArray.Valid, expectedValid);
+        end
+
+        function LogicalValidNVPair(testCase)
+            matlabArray = single([1 2 3]); 
+
+            % Supply a logical vector for Valid
+            arrowArray = arrow.array.Float32Array(matlabArray, Valid=[false; true; true]);
+            testCase.verifyEqual(arrowArray.Valid, [false; true; true]);
+            testCase.verifyEqual(toMATLAB(arrowArray), single([NaN; 2; 3]));
+        end
+
+        function NumericlValidNVPair(testCase)
+            matlabArray = single([1 2 3]); 
+
+            % Supply a numeric vector for Valid 
+            arrowArray = arrow.array.Float32Array(matlabArray, Valid=[1 3]);
+            testCase.verifyEqual(arrowArray.Valid, [true; false; true]);
+            testCase.verifyEqual(toMATLAB(arrowArray), single([1; NaN; 3]));
+        end
     end
 end
diff --git a/matlab/test/arrow/array/tFloat64Array.m b/matlab/test/arrow/array/tFloat64Array.m
index 7248d88e49..68c411da24 100755
--- a/matlab/test/arrow/array/tFloat64Array.m
+++ b/matlab/test/arrow/array/tFloat64Array.m
@@ -23,6 +23,7 @@ classdef tFloat64Array < hNumericArray
         MatlabArrayFcn = @double % double function
         MaxValue = realmax("double")
         MinValue = realmin("double")
+        NullSubstitutionValue = NaN
     end
 
     methods(Test)
diff --git a/matlab/test/arrow/array/tInt32Array.m b/matlab/test/arrow/array/tInt32Array.m
index 705810e6e8..a3ca28b832 100644
--- a/matlab/test/arrow/array/tInt32Array.m
+++ b/matlab/test/arrow/array/tInt32Array.m
@@ -15,7 +15,7 @@
 
 classdef tInt32Array < hNumericArray
 % Tests for arrow.array.Int32Array
-    
+
     properties
         ArrowArrayClassName = "arrow.array.Int32Array"
         ArrowArrayConstructor = @arrow.array.Int32Array
@@ -23,6 +23,6 @@ classdef tInt32Array < hNumericArray
         MatlabArrayFcn = @int32 % int32 function
         MaxValue = intmax("int32")
         MinValue = intmin("int32")
+        NullSubstitutionValue = int32(0)
     end
-
 end
diff --git a/matlab/test/arrow/array/tInt64Array.m b/matlab/test/arrow/array/tInt64Array.m
index c873059edf..846460b576 100644
--- a/matlab/test/arrow/array/tInt64Array.m
+++ b/matlab/test/arrow/array/tInt64Array.m
@@ -23,6 +23,6 @@ classdef tInt64Array < hNumericArray
         MatlabArrayFcn = @int64 % int64 function
         MaxValue = intmax("int64")
         MinValue = intmin("int64")
+        NullSubstitutionValue = int64(0)
     end
-
 end
diff --git a/matlab/test/arrow/array/tInt8Array.m b/matlab/test/arrow/array/tInt8Array.m
index e7cf729fb8..f8c1cf1574 100644
--- a/matlab/test/arrow/array/tInt8Array.m
+++ b/matlab/test/arrow/array/tInt8Array.m
@@ -23,6 +23,7 @@ classdef tInt8Array < hNumericArray
         MatlabArrayFcn = @int8 % int8 function
         MaxValue = intmax("int8")
         MinValue = intmin("int8")
+        NullSubstitutionValue = int8(0)
     end
 
 end
diff --git a/matlab/test/arrow/array/tUInt16Array.m b/matlab/test/arrow/array/tUInt16Array.m
index 7d1ba1618a..5a9eb0ba9c 100644
--- a/matlab/test/arrow/array/tUInt16Array.m
+++ b/matlab/test/arrow/array/tUInt16Array.m
@@ -23,5 +23,6 @@ classdef tUInt16Array < hNumericArray
         MatlabArrayFcn = @uint16 % uint16 function
         MaxValue = intmax("uint16")
         MinValue = intmin("uint16")
+        NullSubstitutionValue = uint16(0)
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/test/arrow/array/tUInt32Array.m b/matlab/test/arrow/array/tUInt32Array.m
index 54a9f1600e..f018f20305 100644
--- a/matlab/test/arrow/array/tUInt32Array.m
+++ b/matlab/test/arrow/array/tUInt32Array.m
@@ -14,8 +14,8 @@
 % permissions and limitations under the License.
 
 classdef tUInt32Array < hNumericArray
-    % Tests for arrow.array.UInt32Array
-    
+% Tests for arrow.array.UInt32Array
+
     properties
         ArrowArrayClassName = "arrow.array.UInt32Array"
         ArrowArrayConstructor = @arrow.array.UInt32Array
@@ -23,5 +23,6 @@ classdef tUInt32Array < hNumericArray
         MatlabArrayFcn = @uint32 % uint32 function
         MaxValue = intmax("uint32")
         MinValue = intmin("uint32")
+        NullSubstitutionValue = uint32(0)
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/test/arrow/array/tUInt64Array.m b/matlab/test/arrow/array/tUInt64Array.m
index 56c0da227e..01edddd86d 100644
--- a/matlab/test/arrow/array/tUInt64Array.m
+++ b/matlab/test/arrow/array/tUInt64Array.m
@@ -1,4 +1,5 @@
 % Licensed to the Apache Software Foundation (ASF) under one or more
+>>>>>>> b27d47fde (Add abstract NumericArray class)
 % 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
@@ -12,7 +13,7 @@
 % 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.
-    
+
 classdef tUInt64Array < hNumericArray
 % Tests for arrow.array.UInt64Array
 
@@ -23,5 +24,6 @@ classdef tUInt64Array < hNumericArray
         MatlabArrayFcn = @uint64 % uint64 function
         MaxValue = intmax("uint64")
         MinValue = intmin("uint64")
+        NullSubstitutionValue = uint64(0)
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/test/arrow/array/tUInt8Array.m b/matlab/test/arrow/array/tUInt8Array.m
index 37fa378a91..e43d646b82 100644
--- a/matlab/test/arrow/array/tUInt8Array.m
+++ b/matlab/test/arrow/array/tUInt8Array.m
@@ -15,7 +15,7 @@
 
 classdef tUInt8Array < hNumericArray
 % Tests for arrow.array.UInt8Array
-    
+
     properties
         ArrowArrayClassName = "arrow.array.UInt8Array"
         ArrowArrayConstructor = @arrow.array.UInt8Array
@@ -23,5 +23,6 @@ classdef tUInt8Array < hNumericArray
         MatlabArrayFcn = @uint8 % uint8 function
         MaxValue = intmax("uint8")
         MinValue = intmin("uint8")
+        NullSubstitutionValue = uint8(0)
     end
-end
\ No newline at end of file
+end