Skip to content

Commit

Permalink
apacheGH-37290: [MATLAB] Add arrow.array.Time32Array class (apache#…
Browse files Browse the repository at this point in the history
…37315)

### Rationale for this change

Now that the `arrow.type.Time32Type` class has been added to the MATLAB Interface (apache#37250), we can add the `arrow.array.Time32Array` class. 

### What changes are included in this PR?

1. Added a new class `arrow.array.Time32Array`. It has the following read-only properties: `Type` and `Length`. It has the following methods: `fromMATLAB()`, `toMATLAB()`, and `duration()`. For reference, `duration` arrays in MATLAB represent lengths of time in fixed-length units. Here's a [link](https://www.mathworks.com/help/matlab/ref/duration.html) to the documentation. 
2. Added a new class called `arrow.type.traits.Time32Traits`.

**Example Usage**

```matlab
>> times = seconds([100 120 NaN 200])

times = 

  1×4 duration array

   100 sec   120 sec   NaN sec   200 sec

>> time32Array = arrow.array.Time32Array.fromMATLAB(times)

time32Array = 

[
  00:01:40,
  00:02:00,
  null,
  00:03:20
]

>> roundtrip = toMATLAB(time32Array)

roundtrip = 

  4×1 duration array

   100 sec
   120 sec
   NaN sec
   200 sec

```

You can also specify the `TimeUnit` to use via a name-value pair. `TimeUnit` can either be `"Second"`  (default) or `"Milisecond"`.

```matlab
>> times = seconds([100 120 NaN 200]);
>> time32Array = arrow.array.Time32Array.fromMATLAB(times, TimeUnit="Millisecond")

time32Array = 

[
  00:01:40.000,
  00:02:00.000,
  null,
  00:03:20.000
]
```

### Are these changes tested?

Yes. Added two new test classes: `tTime32Array.m` and `tTime32Traits.m`.

### Are there any user-facing changes?

Yes, users can now create `arrow.array.Time32Array`s from MATLAB `duration`s via the static `fromMATLAB` method on `arrow.array.Time32Array`.

### Future Directions

1. Add `arrow.array.Time64Array`
2. Add `arrow.type.Date32Type` and `arrow.array.Date32Array`
4. Add `arrow.type.Date64Type` and `arrow.array.Date64Array`

* Closes: apache#37290

Authored-by: Sarah Gilmore <sgilmore@mathworks.com>
Signed-off-by: Sutou Kouhei <kou@clear-code.com>
  • Loading branch information
sgilmore10 authored and loicalleyne committed Nov 13, 2023
1 parent facc083 commit c1c049d
Show file tree
Hide file tree
Showing 11 changed files with 478 additions and 0 deletions.
62 changes: 62 additions & 0 deletions matlab/src/cpp/arrow/matlab/array/proxy/time32_array.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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.

#include "arrow/matlab/array/proxy/time32_array.h"

#include "arrow/matlab/type/time_unit.h"
#include "arrow/util/utf8.h"

namespace arrow::matlab::array::proxy {

// Specialization of NumericArray::Make for arrow::Time32Type
template <>
libmexclass::proxy::MakeResult Time32Array::make(const libmexclass::proxy::FunctionArguments& constructor_arguments) {
namespace mda = ::matlab::data;
using MatlabBuffer = arrow::matlab::buffer::MatlabBuffer;
using Time32Array = arrow::Time32Array;
using Time32ArrayProxy = arrow::matlab::array::proxy::NumericArray<arrow::Time32Type>;

mda::StructArray opts = constructor_arguments[0];

// Get the mxArray from constructor arguments
const mda::TypedArray<int32_t> time32_mda = opts[0]["MatlabArray"];
const mda::TypedArray<bool> validity_bitmap_mda = opts[0]["Valid"];

const mda::TypedArray<mda::MATLABString> units_mda = opts[0]["TimeUnit"];

// extract the time unit
const std::u16string& u16_timeunit = units_mda[0];
MATLAB_ASSIGN_OR_ERROR(const auto time_unit,
arrow::matlab::type::timeUnitFromString(u16_timeunit),
error::UKNOWN_TIME_UNIT_ERROR_ID)

// create the Time32Type
auto data_type = arrow::time32(time_unit);
auto array_length = static_cast<int32_t>(time32_mda.getNumberOfElements()); // cast size_t to int32_t

auto data_buffer = std::make_shared<MatlabBuffer>(time32_mda);

// Pack the validity bitmap values.
MATLAB_ASSIGN_OR_ERROR(auto packed_validity_bitmap,
bit::packValid(validity_bitmap_mda),
error::BITPACK_VALIDITY_BITMAP_ERROR_ID);

auto array_data = arrow::ArrayData::Make(data_type, array_length, {packed_validity_bitmap, data_buffer});
auto time32_array = std::static_pointer_cast<Time32Array>(arrow::MakeArray(array_data));
return std::make_shared<Time32ArrayProxy>(std::move(time32_array));
}
}
31 changes: 31 additions & 0 deletions matlab/src/cpp/arrow/matlab/array/proxy/time32_array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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.

#pragma once

#include "arrow/matlab/array/proxy/numeric_array.h"

#include "arrow/matlab/api/visibility.h"

namespace arrow::matlab::array::proxy {

using Time32Array = NumericArray<arrow::Time32Type>;

// Specialization of NumericArray::Make for arrow::Time32Type
template<>
ARROW_MATLAB_EXPORT libmexclass::proxy::MakeResult Time32Array::make(const libmexclass::proxy::FunctionArguments& constructor_arguments);
}
2 changes: 2 additions & 0 deletions matlab/src/cpp/arrow/matlab/proxy/factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "arrow/matlab/array/proxy/numeric_array.h"
#include "arrow/matlab/array/proxy/string_array.h"
#include "arrow/matlab/array/proxy/timestamp_array.h"
#include "arrow/matlab/array/proxy/time32_array.h"
#include "arrow/matlab/tabular/proxy/record_batch.h"
#include "arrow/matlab/tabular/proxy/schema.h"
#include "arrow/matlab/error/error.h"
Expand Down Expand Up @@ -49,6 +50,7 @@ libmexclass::proxy::MakeResult Factory::make_proxy(const ClassName& class_name,
REGISTER_PROXY(arrow.array.proxy.BooleanArray , arrow::matlab::array::proxy::BooleanArray);
REGISTER_PROXY(arrow.array.proxy.StringArray , arrow::matlab::array::proxy::StringArray);
REGISTER_PROXY(arrow.array.proxy.TimestampArray, arrow::matlab::array::proxy::NumericArray<arrow::TimestampType>);
REGISTER_PROXY(arrow.array.proxy.Time32Array , arrow::matlab::array::proxy::NumericArray<arrow::Time32Type>);
REGISTER_PROXY(arrow.tabular.proxy.RecordBatch , arrow::matlab::tabular::proxy::RecordBatch);
REGISTER_PROXY(arrow.tabular.proxy.Schema , arrow::matlab::tabular::proxy::Schema);
REGISTER_PROXY(arrow.type.proxy.Field , arrow::matlab::type::proxy::Field);
Expand Down
3 changes: 3 additions & 0 deletions matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "arrow/matlab/type/proxy/primitive_ctype.h"
#include "arrow/matlab/type/proxy/timestamp_type.h"
#include "arrow/matlab/type/proxy/time32_type.h"
#include "arrow/matlab/type/proxy/string_type.h"

namespace arrow::matlab::type::proxy {
Expand Down Expand Up @@ -50,6 +51,8 @@ namespace arrow::matlab::type::proxy {
return std::make_shared<PrimitiveCType<double>>(std::static_pointer_cast<arrow::DoubleType>(type));
case ID::TIMESTAMP:
return std::make_shared<TimestampType>(std::static_pointer_cast<arrow::TimestampType>(type));
case ID::TIME32:
return std::make_shared<Time32Type>(std::static_pointer_cast<arrow::Time32Type>(type));
case ID::STRING:
return std::make_shared<StringType>(std::static_pointer_cast<arrow::StringType>(type));
default:
Expand Down
84 changes: 84 additions & 0 deletions matlab/src/matlab/+arrow/+array/Time32Array.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
% arrow.array.Time32Array

% 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.

classdef Time32Array < arrow.array.Array

properties(Access=private)
NullSubstitutionValue = seconds(NaN);
end

methods
function obj = Time32Array(proxy)
arguments
proxy(1, 1) libmexclass.proxy.Proxy {validate(proxy, "arrow.array.proxy.Time32Array")}
end
import arrow.internal.proxy.validate
obj@arrow.array.Array(proxy);
end

function times = toMATLAB(obj)
import arrow.type.TimeUnit

matlabArray = obj.Proxy.toMATLAB();
if obj.Type.TimeUnit == TimeUnit.Second
times = seconds(matlabArray);
else
times = milliseconds(matlabArray);
end
times(~obj.Valid) = obj.NullSubstitutionValue;
end

function times = duration(obj)
times = obj.toMATLAB();
end
end

methods(Static, Access=private)
function ticks = convertDurationToTicks(data, timeUnit)
if (timeUnit == arrow.type.TimeUnit.Second)
ticks = cast(seconds(data), "int32");
else
ticks = cast(milliseconds(data), "int32");
end
end
end

methods(Static)
function array = fromMATLAB(data, opts)
arguments
data
opts.TimeUnit(1, 1) TimeUnit {timeUnit("Time32", opts.TimeUnit)} = TimeUnit.Second
opts.InferNulls(1, 1) logical = true
opts.Valid
end

import arrow.type.TimeUnit
import arrow.array.Time32Array
import arrow.internal.validate.temporal.timeUnit

arrow.internal.validate.type(data, "duration");
arrow.internal.validate.shape(data);

validElements = arrow.internal.validate.parseValidElements(data, opts);
ticks = Time32Array.convertDurationToTicks(data, opts.TimeUnit);

args = struct(MatlabArray=ticks, Valid=validElements, TimeUnit=string(opts.TimeUnit));
proxy = arrow.internal.proxy.create("arrow.array.proxy.Time32Array", args);
array = Time32Array(proxy);
end
end
end
29 changes: 29 additions & 0 deletions matlab/src/matlab/+arrow/+type/+traits/Time32Traits.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
% 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.

classdef Time32Traits < arrow.type.traits.TypeTraits

properties (Constant)
ArrayConstructor = @arrow.array.Time32Array
ArrayClassName = "arrow.array.Time32Array"
ArrayProxyClassName = "arrow.array.proxy.Time32Array"
TypeConstructor = @arrow.type.Time32Type;
TypeClassName = "arrow.type.Time32Type"
TypeProxyClassName = "arrow.type.proxy.Time32Type"
MatlabConstructor = @duration
MatlabClassName = "duration"
end

end
2 changes: 2 additions & 0 deletions matlab/src/matlab/+arrow/+type/+traits/traits.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
typeTraits = StringTraits();
case ID.Timestamp
typeTraits = TimestampTraits();
case ID.Time32
typeTraits = Time32Traits();
otherwise
error("arrow:type:traits:UnsupportedArrowTypeID", "Unsupported Arrow type ID: " + type);
end
Expand Down
Loading

0 comments on commit c1c049d

Please sign in to comment.