File size: 8,671 Bytes
f7ccd08 32b4893 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | { SPDX-License-Identifier: LicenseRef-Sovereign-Leviathan-SL-AGPL3-001
Licensing: see LICENSE in the repository root. }
{ NraayTensor Reference Implementation: Main tensor operations.
Implements core contract operations: ALLOC, FREE, VIEW, SLICE, TRANSPOSE, RESHAPE, MATERIALIZE
Semantic layer:
- Physical Storage: Contiguous buffer managed by tensor_array (Arc semantics)
- Semantic View: Descriptor (shape, strides, offset, governance flags)
- Ownership: Token tracking OWNED/SHARED/EXCLUSIVE state
}
unit tensor;
{$MODE FPC}
interface
uses
descriptor, buffer, tensor_array, ownership, materialize;
type
{ NraayTensor: Semantic view + physical storage }
TNraayTensor = record
{ Physical buffer (Arc-wrapped) }
data: TTensorArray;
{ Semantic descriptor }
descriptor: TTensorDescriptor;
{ Ownership token }
ownership: TOwnershipToken;
{ Shape array (must persist for descriptor) }
shape: array of uint32;
{ Strides array (must persist for descriptor) }
strides: array of uint32;
end;
{ Operation result }
TTensorResult = (
TR_SUCCESS,
TR_INVALID_SHAPE,
TR_DIMENSION_MISMATCH,
TR_OUT_OF_BOUNDS,
TR_INVALID_PERMUTATION,
TR_ALLOCATION_FAILED,
TR_NULL_POINTER
);
{ Create tensor with given shape (ALLOC operation) }
function CreateTensor(const shape: array of uint32): TNraayTensor;
{ Clone tensor (increment refcount, shared ownership) }
function CloneTensor(const t: TNraayTensor): TNraayTensor;
{ Destroy tensor (decrement refcount) }
procedure DestroyTensor(var t: TNraayTensor);
{ Get element at coordinate }
function GetElement(const t: TNraayTensor; const coord: array of uint32): single;
{ Set element at coordinate }
procedure SetElement(var t: TNraayTensor; const coord: array of uint32; value: single);
{ Virtual slicing: zero-copy view with ranges (start, end, step) }
function Slice(
const t: TNraayTensor;
const ranges: array of array of uint32
): TNraayTensor;
{ Transpose via permutation (axes rearrangement) }
function Transpose(
const t: TNraayTensor;
const perm: array of uint32
): TNraayTensor;
{ Materialize tensor (restore contiguity and exclusive ownership) }
procedure Materialize(var t: TNraayTensor);
{ Check if tensor is valid }
function IsValid(const t: TNraayTensor): boolean;
{ Get total element count }
function Length(const t: TNraayTensor): uint32;
{ Get rank }
function Rank(const t: TNraayTensor): uint32;
{ Compute canonical strides for shape }
procedure ComputeStrides(const shape: array of uint32; var strides: array of uint32);
{ Result code to string }
function ResultToString(result: TTensorResult): string;
implementation
procedure ComputeStrides(const shape: array of uint32; var strides: array of uint32);
var
i, stride: uint32;
begin
stride := 1;
for i := high(shape) downto 0 do
begin
strides[i] := stride;
stride := stride * shape[i];
end;
end;
function CreateTensor(const shape: array of uint32): TNraayTensor;
var
size: uint32;
i: uint32;
begin
setlength(result.shape, length(shape));
setlength(result.strides, length(shape));
{ Copy shape }
size := 1;
for i := 0 to high(shape) do
begin
result.shape[i] := shape[i];
size := size * shape[i];
end;
{ Compute strides }
ComputeStrides(result.shape, result.strides);
{ Allocate buffer }
result.data := CreateTensorArray(size);
{ Create descriptor }
with result.descriptor do
begin
rank := length(shape);
shape_ptr := @result.shape[0];
strides_ptr := @result.strides[0];
offset := 0;
len := size;
is_contiguous := 1;
owns_storage := 1;
generation := 0;
end;
{ Initialize ownership }
result.ownership := CreateOwnershipToken(result.descriptor.generation);
end;
function CloneTensor(const t: TNraayTensor): TNraayTensor;
begin
result := t;
result.data := CloneTensorArray(t.data);
result.ownership := TransitionToShared(t.ownership);
end;
procedure DestroyTensor(var t: TNraayTensor);
begin
DropTensorArray(t.data);
setlength(t.shape, 0);
setlength(t.strides, 0);
end;
function GetElement(const t: TNraayTensor; const coord: array of uint32): single;
var
i, offset: uint32;
begin
if length(coord) <> t.descriptor.rank then
exit(0.0);
offset := t.descriptor.offset;
for i := 0 to t.descriptor.rank - 1 do
begin
if coord[i] >= t.descriptor.shape_ptr^[i] then
exit(0.0);
offset := offset + coord[i] * t.descriptor.strides_ptr^[i];
end;
result := GetElement(t.data, offset);
end;
procedure SetElement(var t: TNraayTensor; const coord: array of uint32; value: single);
var
i, offset: uint32;
begin
if length(coord) <> t.descriptor.rank then
exit;
offset := t.descriptor.offset;
for i := 0 to t.descriptor.rank - 1 do
begin
if coord[i] >= t.descriptor.shape_ptr^[i] then
exit;
offset := offset + coord[i] * t.descriptor.strides_ptr^[i];
end;
SetElement(t.data, offset, value);
end;
function Slice(
const t: TNraayTensor;
const ranges: array of array of uint32
): TNraayTensor;
var
i, j: uint32;
new_shape: array of uint32;
new_strides: array of uint32;
new_offset: uint32;
begin
if length(ranges) <> t.descriptor.rank then
exit(t); { Invalid dimensions }
setlength(new_shape, t.descriptor.rank);
setlength(new_strides, t.descriptor.rank);
new_offset := t.descriptor.offset;
for i := 0 to t.descriptor.rank - 1 do
begin
if length(ranges[i]) < 3 then
exit(t); { Invalid range format }
with ranges[i] do
begin
if (ranges[i][0] >= t.descriptor.shape_ptr^[i]) or
(ranges[i][1] > t.descriptor.shape_ptr^[i]) or
(ranges[i][0] >= ranges[i][1]) or
(ranges[i][2] = 0) then
exit(t); { Invalid slice }
end;
new_shape[i] := (ranges[i][1] - ranges[i][0] + ranges[i][2] - 1) div ranges[i][2];
new_offset := new_offset + ranges[i][0] * t.descriptor.strides_ptr^[i];
new_strides[i] := t.descriptor.strides_ptr^[i] * ranges[i][2];
end;
result := t;
result.shape := new_shape;
result.strides := new_strides;
result.descriptor.shape_ptr := @result.shape[0];
result.descriptor.strides_ptr := @result.strides[0];
result.descriptor.offset := new_offset;
result.descriptor.is_contiguous := 0;
result.descriptor.owns_storage := 0;
result.ownership := TransitionToShared(t.ownership);
end;
function Transpose(
const t: TNraayTensor;
const perm: array of uint32
): TNraayTensor;
var
i: uint32;
new_shape: array of uint32;
new_strides: array of uint32;
begin
if length(perm) <> t.descriptor.rank then
exit(t);
setlength(new_shape, t.descriptor.rank);
setlength(new_strides, t.descriptor.rank);
for i := 0 to t.descriptor.rank - 1 do
begin
if perm[i] >= t.descriptor.rank then
exit(t); { Invalid permutation }
new_shape[i] := t.descriptor.shape_ptr^[perm[i]];
new_strides[i] := t.descriptor.strides_ptr^[perm[i]];
end;
result := t;
result.shape := new_shape;
result.strides := new_strides;
result.descriptor.shape_ptr := @result.shape[0];
result.descriptor.strides_ptr := @result.strides[0];
result.descriptor.is_contiguous := 0;
end;
procedure Materialize(var t: TNraayTensor);
var
mat_result: TMaterializationResult;
begin
mat_result := MaterializeTensorArray(t.data, t.descriptor);
if mat_result.success then
begin
{ Reset strides to canonical }
ComputeStrides(t.shape, t.strides);
t.descriptor.offset := 0;
t.descriptor.is_contiguous := 1;
t.descriptor.owns_storage := 1;
t.descriptor.generation := mat_result.new_generation;
t.ownership := TransitionToExclusive(t.ownership, mat_result.new_generation);
end;
end;
function IsValid(const t: TNraayTensor): boolean;
begin
result := (GetSize(t.data) > 0) and
(t.descriptor.rank > 0) and
(t.descriptor.len > 0);
end;
function Length(const t: TNraayTensor): uint32;
begin
result := t.descriptor.len;
end;
function Rank(const t: TNraayTensor): uint32;
begin
result := t.descriptor.rank;
end;
function ResultToString(result: TTensorResult): string;
begin
case result of
TR_SUCCESS:
ResultToString := 'SUCCESS';
TR_INVALID_SHAPE:
ResultToString := 'INVALID_SHAPE';
TR_DIMENSION_MISMATCH:
ResultToString := 'DIMENSION_MISMATCH';
TR_OUT_OF_BOUNDS:
ResultToString := 'OUT_OF_BOUNDS';
TR_INVALID_PERMUTATION:
ResultToString := 'INVALID_PERMUTATION';
TR_ALLOCATION_FAILED:
ResultToString := 'ALLOCATION_FAILED';
TR_NULL_POINTER:
ResultToString := 'NULL_POINTER';
else
ResultToString := 'UNKNOWN';
end;
end;
end.
|