Einzelnen Beitrag anzeigen

bernhard_LA

Registriert seit: 8. Jun 2009
Ort: Bayern
1.124 Beiträge
 
Delphi 11 Alexandria
 
#1

Einfache Version von Numpy in Delphi nachbauen

  Alt 3. Jan 2024, 07:53
Ich will Python-Code unter Delphi nachbauen und dann in einem weiteren Schritt mit meinen eigenen Ideen , Bibliotheken auf meine eigentliche Aufgabenstellung anpassen.
Ich brauche im ersten Schritt um im Programm-Ablauf identisch zum Original-Code zu bleiben, eine "Mini"-Numpy Emulierung. Weiter unten habe ich meine "Spielversion" - eingefügt.

Meine Frage : was wäre die beste Lösung um alle ArrayTypen (Integer, Float, Bool) zu unterstützen ? Wie würde man am elegantesten 2D und 3D Array Typen untertützen , dh. eine Interpretation meines 1D-Arrays in 2D oder 3D
.


Delphi-Quellcode:
var
  A: TNDArray;
  i, j: Integer;
  NumPy : TNumPy;
begin

  A := TNumPy.ToArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);

  // Save the 2D array as a CSV file
  TNumPy.Shape(4, 4); // Set the shape of the array

  TNumPy.Savetxt('c:\temp\output.csv', A ); // Save the array as a CSV file
end ;



Andere Ideen zu diesem Projekt, bin für alle Anmerkungen offen









Delphi-Quellcode:
unit Unit_NumPy;

interface

uses
  System.Classes, System.SysUtils, System.Generics.Collections, System.Math;

type
  T2DDoubleArray = array of array of Double;
  TNDArray = TArray<Double>;
  TNDArray2 = TArray<TNDArray> ;
  TByteArray = TArray<Byte>;
  TBoolArray = Tarray<Boolean>;
  TCardinalArray = TArray<Cardinal>;
  TIntegerArray = TArray<Integer>;


  TNumPy = class
  class var
    FWidth: Integer;
    FHeight: Integer;

  private


  public
    class function arange(const start, stop, step: Double): TNDArray; static;
    class function ToArray(const Values: array of Double): TNDArray; overload; static;
    class function ToArray(const Values: T2DDoubleArray): TArray<TNDArray>; overload; static;
    class function diff(const a: TNDArray): TNDArray; static;
    class function mean(const a: TNDArray): Double; static;
    class function sum(const a: TNDArray): Double; static;
    class function prod(const a: TNDArray): Double; static;
    class function ConvertByteArrayToNDArray(const a: TByteArray)
      : TNDArray; static;
    class function max(const a: TNDArray): Double; static;
    class function min(const a: TNDArray): Double; static;
    class function unique(const a: TNDArray): TNDArray; static;
    class function isnan(const a: TNDArray): TBoolArray; static;
    class function all(const a: TNDArray): Boolean;
    class procedure Shape(X, y: Integer);
    class procedure Savetxt(const fname: string; const X: TNDArray;
      const fmt: string = '%.18e'; const delimiter: string = ';';
      const newline: string = #10; const header: string = '';
      const footer: string = ''; const comments: string = '# ';
      const encoding: TEncoding = nil);

  end;

implementation

{ TNumPy }


class function TNumPy.min(const a: TNDArray): Double;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a);

  if n = 0 then
    Exit(0);

  Result := a[0];

  for i := 1 to n - 1 do
    if a[i] < Result then
      Result := a[i];
end;



class function TNumPy.max(const a: TNDArray): Double;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a);

  if n = 0 then
    Exit(0);

  Result := a[0];

  for i := 1 to n - 1 do
    if a[i] > Result then
      Result := a[i];
end;



class function TNumPy.ToArray(const Values: array of Double): TNDArray;
var
  i: Integer;
begin
  SetLength(Result, Length(Values));
  for i := 0 to High(Values) do
    Result[i] := Values[i];
end;


class function TNumPy.isnan(const a: TNDArray): TBoolArray;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a);
  SetLength(Result, n);

  for i := 0 to n - 1 do
    Result[i] := System.Math.IsNan(a[i]);
end;

class function TNumPy.ToArray(const Values: T2DDoubleArray): TArray<TNDArray>;
var
  i, j: Integer;
begin
  SetLength(Result, Length(Values));
  for i := 0 to High(Values) do
  begin
    SetLength(Result[i], Length(Values[i]));
    for j := 0 to High(Values[i]) do
      Result[i][j] := Values[i][j];
  end;
end;

class function TNumPy.arange(const start, stop, step: Double): TNDArray;
var
  i: Integer;
  n: Integer;
begin
  n := Round((stop - start) / step);
  SetLength(Result, n);

  for i := 0 to n - 1 do
    Result[i] := start + i * step;
end;

class function TNumPy.ConvertByteArrayToNDArray(const a: TByteArray): TNDArray;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a);
  SetLength(Result, n);

  for i := 0 to n - 1 do
    Result[i] := a[i];
end;

class function TNumPy.diff(const a: TNDArray): TNDArray;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a) - 1;
  SetLength(Result, n);

  for i := 0 to n - 1 do
    Result[i] := a[i + 1] - a[i];
end;

class function TNumPy.mean(const a: TNDArray): Double;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a);

  if n = 0 then
    Exit(0);

  Result := 0;

  for i := 0 to n - 1 do
    Result := Result + a[i];

  Result := Result / n;
end;

class function TNumPy.prod(const a: TNDArray): Double;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a);
  Result := 1;

  for i := 0 to n - 1 do
    Result := Result * a[i];
end;

class procedure TNumPy.Shape(X, y: Integer);
begin
  FWidth := X;
  FHeight := y;
end;

class function TNumPy.unique(const a: TNDArray): TNDArray;
var
  i, j: Integer;
  temp: Double;
  uniqueArr: TList<Double>;
begin
  uniqueArr := TList<Double>.Create;

  try
    for i := 0 to Length(a) - 1 do
    begin
      temp := a[i];
      if not uniqueArr.Contains(temp) then
        uniqueArr.Add(temp);
    end;

    SetLength(Result, uniqueArr.Count);

    for j := 0 to uniqueArr.Count - 1 do
      Result[j] := uniqueArr[j];

  finally
    uniqueArr.Free;
  end;
end;

class function TNumPy.sum(const a: TNDArray): Double;
var
  i: Integer;
  n: Integer;
begin
  n := Length(a);
  Result := 0;

  for i := 0 to n - 1 do
    Result := Result + a[i];
end;

class procedure TNumPy.Savetxt(const fname: string; const X: TNDArray;
  const fmt: string = '%.18e'; const delimiter: string = ';';
  const newline: string = #10; const header: string = '';
  const footer: string = ''; const comments: string = '# ';
  const encoding: TEncoding = nil);
var
  sl: TStringList;
  i, j: Integer;
  row: string;
  width, height: Integer;
begin
  width := FWidth;
  Height := FHeight;

  if (width = 0) or (height = 0) then
    raise Exception.Create('Invalid array shape');

  sl := TStringList.Create;

  try
    if header <> 'then
      sl.Add(comments + header);

    for i := 0 to height - 1 do
    begin
      row := Format(fmt, [X[i * width]]);
      for j := 1 to width - 1 do
        row := row + delimiter + Format(fmt, [X[i * width + j]]);
      sl.Add(row);
    end;

    if footer <> 'then
      sl.Add(comments + footer);

    sl.SaveToFile(fname, encoding);

  finally
    sl.Free;
  end;
end;


class function TNumPy.all(const a: TNDArray): Boolean;
var
  i: Integer;
begin
  for i := 0 to Length(a) - 1 do
  begin
    if not (a[i] <> 0) then
    begin
      Result := False;
      Exit;
    end;
  end;
  Result := True;
end;

end.

Geändert von bernhard_LA ( 3. Jan 2024 um 07:55 Uhr)
  Mit Zitat antworten Zitat