Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add experimental dimension label APIs #258

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
201 changes: 201 additions & 0 deletions examples/TileDB.CSharp.Example/ExampleDimensionLabels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
using System;
using System.IO;
using System.Linq;

namespace TileDB.CSharp.Examples
{
public static class ExampleDimensionLabels
{
private static readonly string ArrayPath = ExampleUtil.MakeExamplePath("dimension-labels");
private static readonly Context Ctx = Context.GetDefault();

private static void CreateArray()
{
using var xIndex = Dimension.Create(Ctx, "x_index", 0, 5, 6);
using var sample = Dimension.Create(Ctx, "sample", 0, 3, 4);

using var domain = new Domain(Ctx);
domain.AddDimensions(xIndex, sample);

using var a = Attribute.Create<short>(Ctx, "a");

using var schema = new ArraySchema(Ctx, ArrayType.Dense);
schema.SetCellOrder(LayoutType.RowMajor);
schema.SetTileOrder(LayoutType.RowMajor);
schema.SetDomain(domain);
schema.AddAttribute(a);
schema.AddDimensionLabel(0, "x", DataOrder.Increasing, DataType.Float64);
schema.AddDimensionLabel(0, "y", DataOrder.Increasing, DataType.Float64);
schema.AddDimensionLabel(1, "timestamp", DataOrder.Increasing, DataType.DateTimeSecond);

Array.Create(Ctx, ArrayPath, schema);
}

private static void WriteArrayAndLabels()
{
short[] a = Enumerable.Range(1, 24).Select(x => (short)x).ToArray();
double[] x = { -1.0, -0.6, -0.2, 0.2, 0.6, 1.0 };
double[] y = { 0.0, 2.0, 4.0, 6.0, 8.0, 10.0 };
long[] timestamp = { 31943, 32380, 33131, 33228 };

using Array array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Write);

using Query query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetDataBuffer("a", a);
query.SetDataBuffer("x", x);
query.SetDataBuffer("y", y);
query.SetDataBuffer("timestamp", timestamp);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Write query did not complete.");
}

array.Close();
}

private static void ReadArrayAndLabels()
{
Console.WriteLine("Read from main array");

using var array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Read);

using var subarray = new Subarray(array);
subarray.AddRange(0, 1, 2);
subarray.AddRange(1, 0, 2);

short[] a = new short[6];
double[] x = new double[2];
double[] y = new double[2];
long[] timestamp = new long[3];

using var query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetSubarray(subarray);
query.SetDataBuffer("a", a);
query.SetDataBuffer("x", x);
query.SetDataBuffer("y", y);
query.SetDataBuffer("timestamp", timestamp);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Read query did not complete.");
}

for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
int x_val = i + 1;
int sample_val = j;
Console.WriteLine($"Cell ({x_val}, {sample_val})");
Console.WriteLine($" * a({x_val}, {sample_val}) = {a[3 * i + j]}");
Console.WriteLine($" * x({x_val}) = {x[i]}");
Console.WriteLine($" * y({x_val}) = {y[i]}");
Console.WriteLine($" * timestamp({sample_val}) = {TimeSpan.FromSeconds(timestamp[j])}");
}
}

array.Close();
}

private static void ReadTimestampData()
{
Console.WriteLine("Read from dimension label");

using var array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Read);

using var subarray = new Subarray(array);
subarray.AddRange(1, 1, 3);

long[] timestamp = new long[3];

using var query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetSubarray(subarray);
query.SetDataBuffer("timestamp", timestamp);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Read query did not complete.");
}

for (int i = 0; i < 3; i++)
{
int sample_val = i + 1;
Console.WriteLine($"Cell ({sample_val})");
Console.WriteLine($" * timestamp({sample_val}) = {TimeSpan.FromSeconds(timestamp[i])}");
}

array.Close();
}

private static void ReadArrayByLabel()
{
Console.WriteLine("Read array from label ranges");

using var array = new Array(Ctx, ArrayPath);
array.Open(QueryType.Read);

using var subarray = new Subarray(array);
subarray.AddLabelRange("y", 3.0, 8.0);
subarray.AddLabelRange<long>("timestamp", 31943, 32380);

short[] a = new short[6];
double[] y = new double[3];
long[] timestamp = new long[2];

using var query = new Query(Ctx, array);
query.SetLayout(LayoutType.RowMajor);
query.SetSubarray(subarray);
query.SetDataBuffer("y", y);
query.SetDataBuffer("timestamp", timestamp);
query.SetDataBuffer("a", a);

query.Submit();

if (query.Status() != QueryStatus.Completed)
{
throw new Exception("Read query did not complete.");
}

for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine($"Cell ({y[i]}, {TimeSpan.FromSeconds(timestamp[j])})");
Console.WriteLine($" * a = {a[2 * i + j]}");
}
}

array.Close();
}

public static void Run()
{
if (Directory.Exists(ArrayPath))
{
Directory.Delete(ArrayPath, true);
}

CreateArray();
WriteArrayAndLabels();
ReadArrayAndLabels();
Console.WriteLine();
ReadTimestampData();
Console.WriteLine();
ReadArrayByLabel();
Console.WriteLine();
}
}
}
3 changes: 2 additions & 1 deletion examples/TileDB.CSharp.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using TileDB.CSharp;
namespace TileDB.CSharp.Examples;
Expand All @@ -17,6 +17,7 @@ static void Main(string[] args)
ExampleWritingSparseGlobal.Run();
ExampleDataframe.Run();
ExampleAggregateQuery.Run();
ExampleDimensionLabels.Run();

ExampleFile.RunLocal();
// ExampleFile.RunCloud("tiledb_api_token", "tiledb_namespace", "new_cloud_array_name", "s3://bucket/prefix/");
Expand Down
106 changes: 106 additions & 0 deletions sources/TileDB.CSharp/ArraySchema.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using TileDB.CSharp.Marshalling.SafeHandles;
using TileDB.Interop;
using ArraySchemaHandle = TileDB.CSharp.Marshalling.SafeHandles.ArraySchemaHandle;
Expand Down Expand Up @@ -81,6 +82,46 @@ public void AddEnumeration(Enumeration enumeration)
_ctx.handle_error(Methods.tiledb_array_schema_add_enumeration(ctxHandle, handle, enumHandle));
}

/// <summary>
/// Adds a dimension label to the <see cref="ArraySchema"/>.
/// </summary>
/// <param name="dimensionIndex">The dimension's index.</param>
/// <param name="name">The dimension label's name.</param>
/// <param name="labelOrder">The data order of the dimension label.</param>
/// <param name="labelType">The dimension lable's data type.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public void AddDimensionLabel(uint dimensionIndex, string name, DataOrder labelOrder, DataType labelType)
{
using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
_ctx.handle_error(Methods.tiledb_array_schema_add_dimension_label(ctxHandle, handle, dimensionIndex, ms_name, (tiledb_data_order_t)labelOrder, (tiledb_datatype_t)labelType));
}

/// <summary>
/// Adds a dimension label to the <see cref="ArraySchema"/>, that has a specified tile extent.
/// </summary>
/// <param name="dimensionIndex">The dimension's index.</param>
/// <param name="name">The dimension label's name.</param>
/// <param name="labelOrder">The data order of the dimension label.</param>
/// <param name="labelType">The dimension lable's data type.</param>
/// <param name="extent">The dimension label's tile extent.</param>
/// <exception cref="InvalidOperationException"><typeparamref name="T"/> and <paramref name="labelType"/> do not match.</exception>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public void AddDimensionLabel<T>(uint dimensionIndex, string name, DataOrder labelOrder, DataType labelType, T extent) where T : struct
{
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>() || typeof(T) != EnumUtil.DataTypeToType(labelType))
{
ThrowHelpers.ThrowTypeMismatch(labelType);
}

using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
_ctx.handle_error(Methods.tiledb_array_schema_add_dimension_label(ctxHandle, handle, dimensionIndex, ms_name, (tiledb_data_order_t)labelOrder, (tiledb_datatype_t)labelType));
_ctx.handle_error(Methods.tiledb_array_schema_set_dimension_label_tile_extent(ctxHandle, handle, ms_name, (tiledb_datatype_t)labelType, &extent));
}

/// <summary>
/// Sets whether cells with duplicate coordinates are allowed in the <see cref="ArraySchema"/>.
/// </summary>
Expand Down Expand Up @@ -145,6 +186,21 @@ public void SetCellOrder(LayoutType layoutType)
_ctx.handle_error(Methods.tiledb_array_schema_set_cell_order(ctxHandle, handle, tiledb_layout));
}

/// <summary>
/// Sets the <see cref="FilterList"/> of filters that will be applied in one of the <see cref="ArraySchema"/>'s dimension labels.
/// </summary>
/// <param name="name">The dimension label's name.</param>
/// <param name="filterList">The dimension label's filter list.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public void SetDimensionLabelFilterList(string name, FilterList filterList)
{
using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
using var filterListHandle = filterList.Handle.Acquire();
_ctx.handle_error(Methods.tiledb_array_schema_set_dimension_label_filter_list(ctxHandle, handle, ms_name, filterListHandle));
}

/// <summary>
/// Sets the <see cref="ArraySchema"/>'s tile order.
/// </summary>
Expand Down Expand Up @@ -491,6 +547,56 @@ public bool HasAttribute(string name)
return has_attr > 0;
}

/// <summary>
/// Gets a <see cref="CSharp.DimensionLabel"/> from the <see cref="ArraySchema"/> by name.
/// </summary>
/// <param name="name">The dimension label's name.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public DimensionLabel DimensionLabel(string name)
{
var handle = new DimensionLabelHandle();
var successful = false;
tiledb_dimension_label_t* dimension_label_p = null;
try
{
using (var ctxHandle = _ctx.Handle.Acquire())
using (var schemaHandle = _handle.Acquire())
using (var ms_name = new MarshaledString(name))
{
_ctx.handle_error(Methods.tiledb_array_schema_get_dimension_label_from_name(ctxHandle, schemaHandle, ms_name, &dimension_label_p));
}
successful = true;
}
finally
{
if (successful)
{
handle.InitHandle(dimension_label_p);
}
else
{
handle.SetHandleAsInvalid();
}
}

return new DimensionLabel(_ctx, handle);
}

/// <summary>
/// Checks if a dimension label with the given name exists in the <see cref="ArraySchema"/> or not.
/// </summary>
/// <param name="name">The name to check.</param>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public bool HasDimensionLabel(string name)
{
int has_attr;
using var ctxHandle = _ctx.Handle.Acquire();
using var handle = _handle.Acquire();
using var ms_name = new MarshaledString(name);
_ctx.handle_error(Methods.tiledb_array_schema_has_dimension_label(ctxHandle, handle, ms_name, &has_attr));
return has_attr > 0;
}

/// <summary>
/// Load an <see cref="ArraySchema"/> from a URI.
/// </summary>
Expand Down
24 changes: 24 additions & 0 deletions sources/TileDB.CSharp/DataOrder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using TileDB.Interop;

namespace TileDB.CSharp
{
/// <summary>
/// Specifies the order of data in dimension labels.
/// </summary>
/// <remarks>This API is experimental and subject to breaking changes without advance notice.</remarks>
public enum DataOrder
{
/// <summary>
/// Data are not ordered.
/// </summary>
Unordered = tiledb_data_order_t.TILEDB_UNORDERED_DATA,
/// <summary>
/// Data are stored in increasing order.
/// </summary>
Increasing = tiledb_data_order_t.TILEDB_INCREASING_DATA,
/// <summary>
/// Data are stored in decreasing order.
/// </summary>
Decreasing = tiledb_data_order_t.TILEDB_DECREASING_DATA
}
}
Loading
Loading