ASObjects.pas

File name
C:\Users\Andreas Rejbrand\Documents\Dev\AlgoSim\ASObjects.pas
Date exported
Time exported
Formatting processor
TPascalFormattingProcessor
unit ASObjects;

{ **************************************************************************** }
{ Rejbrand AlgoSim Kernel object data types                                    }
{ Copyright © 2017-2020 Andreas Rejbrand                                       }
{ https://english.rejbrand.se/                                                 }
{ **************************************************************************** }

{$WARN SYMBOL_PLATFORM OFF}
{$WARN DUPLICATE_CTOR_DTOR OFF}

interface

uses
  ASStrFcns, SysUtils, Types, Classes, ASNum, ASPixmap, ASSounds, ASKernelDefs,
  Generics.Defaults, Generics.Collections, ASTable, ASColors, Math, UITypes,
  GenHelpers;

type
  TAlgosimObjectClassFlag = (asoObjectContainer, asoValueContainer,
    asoOrderedContainer, asoPlanarContainer, asoComplex);
  TAlgosimObjectClassFlags = set of TAlgosimObjectClassFlag;

  TAlgosimObjectClassData = record
    ClassTypeName: string;
    ClassFlags: TAlgosimObjectClassFlags;
    ExportExts: TArray<string>;
    constructor Create(const AClassTypeName: string;
      AClassFlags: TAlgosimObjectClassFlags = [];
      const AExportExts: string = '');
  end;

  AlgosimObjectAttribute = class(TCustomAttribute)
    Data: TAlgosimObjectClassData;
    constructor Create(const AClassTypeName: string;
      AClassFlags: TAlgosimObjectClassFlags = [];
      const AExportExts: string = '');
  end;

  TAlgosimObject = class;
  TAlgosimNumericEntity = class;
  TAlgosimNumericArray = class;
  TAlgosimNumber = class;
  TAlgosimArray = class;
  TAlgosimVector = class;
  TAlgosimMatrix = class;
  TAlgosimSet = class;
  TAlgosimBinaryData = class;
  TAlgosimStructure = class;
  TAlgosimStructureType = class;

  TAlgosimObjectClass = class of TAlgosimObject;
  TAlgosimNumericEntityClass = class of TAlgosimNumericEntity;
  TAlgosimNumericArrayClass = class of TAlgosimNumericArray;
  TAlgosimNumberClass = class of TAlgosimNumber;
  TAlgosimArrayClass = class of TAlgosimArray;
  TAlgosimVectorClass = class of TAlgosimVector;
  TAlgosimMatrixClass = class of TAlgosimMatrix;
  TAlgosimSetClass = class of TAlgosimSet;
  TAlgosimBinaryDataClass = class of TAlgosimBinaryData;
  TAlgosimStructureClass = class of TAlgosimStructure;
  TAlgosimStructureTypeClass = class of TAlgosimStructureType;

  /// <summary>An AlgoSim object predicate.</summary>
  /// <param name="AObject">The object. The function MUST consider it read-only
  ///  and will NOT gain ownership of it.</param>
  TASOPredicate = reference to function(AObject: TAlgosimObject): Boolean;

  /// <summary>An AlgoSim object function.</summary>
  /// <param name="AObject">The object. The function MUST consider it read-only
  ///  and will NOT gain ownership of it.</param>
  /// <returns>A new object. The caller gains ownership of the object.</returns>
  TASOFunction = reference to function(AObject: TAlgosimObject): TAlgosimObject;

  /// <summary>An AlgoSim object accumulator.</summary>
  /// <param name="CurVal">The accumulated value so far. The function MUST
  ///  consider it read-only and will NOT gain ownership of it.</param>
  /// <param name="NewVal">The new value to add to the accumulated value. The
  ///  function MUST consider it read-only and will NOT gain ownership of it.
  ///  </param>
  /// <returns>The new accumulated value. The caller gains ownership of the
  ///  object.</returns>
  TASOAccumulator = reference to function(CurVal, NewVal: TAlgosimObject): TAlgosimObject;

  TSubscriptKind = (skIndexObject, skIdentifier, skFirst, skLast, skRandom,
    skRowIndex, skColIndex, skMainDiagonal, skSuperdiagonal, skSubdiagonal,
    skAntidiagonal);

  TSubscript = record
    Kind: TSubscriptKind;
    Ident: string;
    Obj: TAlgosimObject;
    Ordinal: Integer;
    constructor Create(const AIdent: string); overload;
    constructor Create(const AIndex: TAlgosimObject); overload;
    constructor Create(const AKind: TSubscriptKind; const AOrd: Integer = 0); overload;
    function ToString: string;
  end;

  TSortClass = (
    SORTCLASS_NULL,
    SORTCLASS_BOOLEAN,
    SORTCLASS_NUMBER,
    SORTCLASS_TEXT,
    SORTCLASS_VECTOR,
    SORTCLASS_MATRIX,
    SORTCLASS_TABLE,
    SORTCLASS_COLOR,
    SORTCLASS_PIXMAP,
    SORTCLASS_SOUND,
    SORTCLASS_ARRAY,
    SORTCLASS_SET,
    SORTCLASS_STRUCTURE,
    SORTCLASS_BINARYDATA,
    SORTCLASS_SUCCESS,
    SORTCLASS_CONTROL);

  PAlgosimObject = ^TAlgosimObject;

  [AlgosimObject('object')]
  TAlgosimObject = class abstract
  public const
    EllipsisSymbol = #$FDE0 {noncharacter};
    EllipsisSymbol_HORIZONTAL_ELLIPSIS = #$2026;
    EllipsisSymbol_VERTICAL_ELLIPSIS = #$22EE;
    EllipsisSymbol_MIDLINE_HORIZONTAL_ELLIPSIS = #$22EF;
    EllipsisSymbol_DOWN_RIGHT_DIAGONAL_ELLIPSIS = #$22F1;
  private

    /// <summary>Returns the sum of all numbers contanied in the object. Raises
    ///  an exception if the object contains other kinds of objects than
    ///  numbers. The empty sum is 0.</summary>
    /// <returns>The desired sum as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_NumberSum: TAlgosimNumber;

    /// <summary>Returns the sum of all vectors contanied in the object. Raises
    ///  an exception if the object contains other kinds of objects than
    ///  vectors, if the vectors are of different dimensions, or if the object
    //   contains no vectors.</summary>
    /// <returns>The desired sum as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_VectorSum: TAlgosimVector;

    /// <summary>Returns the sum of all matrices contanied in the object. Raises
    ///  an exception if the object contains other kinds of objects than
    ///  matrices, if the matrices are of different sizes, or if the object
    //   contains no matrices.</summary>
    /// <returns>The desired sum as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_MatrixSum: TAlgosimMatrix;

    /// <summary>Returns the product of all numbers contanied in the object.
    ///  Raises an exception if the object contains other kinds of objects than
    ///  numbers. The empty product is 1.</summary>
    /// <returns>The desired product as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_NumberProduct: TAlgosimNumber;

    /// <summary>Returns the product of all matrices contanied in the object.
    ///  Raises an exception if the object contains other kinds of objects than
    ///  matrices, if the matrices are not square and of the same size, or if
    ///  the object contains no matrices.</summary>
    /// <returns>The desired product as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_MatrixProduct: TAlgosimMatrix;

  protected

    procedure NoCopyConstr(AFrom: TAlgosimObject);
    function GetTypeName: string; virtual;
    function GetElement(Index: Integer): TAlgosimObject; virtual;
    function GetElementCount: Integer; virtual;
    procedure SetElement(Index: Integer; AValue: TAlgosimObject); virtual;
    function GetCapacity: Integer; virtual;
    procedure SetCapacity(const Value: Integer); virtual;
    function GetValue(Index: Integer): TAlgosimObject; virtual;
    function GetValueCount: Integer; virtual;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); virtual;
    function GetPlanarExtent: TSize; virtual;
    procedure SetPlanarExtent(const Value: TSize); virtual;
    function GetValueFromPoint(const APoint: TPoint): TAlgosimObject; virtual;
    procedure SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject); virtual;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); virtual;
    procedure AddMembersToArray(AArray: TAlgosimArray;
      APredicate: TASOPredicate; ALevel: Integer); overload;
    procedure AddMembersToArray(AArray: TAlgosimArray;
      APredicate: TASOPredicate); overload;
    function GetIsComplex: Boolean; virtual;
    function GetMaxLen: Integer; virtual;
    procedure SetMaxLen(AValue: Integer); virtual;
    class function GetPhysIndex0(AIndex, ALength: Integer): Integer; static;
    class function GetPhysIndex1(AIndex, ALength: Integer): Integer; static;
    class function GetPhysIndex2D0(const AIndex: TPoint; const ASize: TSize): TPoint; static;
    function GetMemorySize: UInt64; virtual;

  public

    constructor Create; overload; virtual;

    function ASOClassType: TAlgosimObjectClass; inline;

    class var _ASOClassData: TDictionary<TAlgosimObjectClass, TAlgosimObjectClassData>;
    class constructor ClassCreate;
    class destructor ClassDestroy;

    class function EqualityComparison(const Left, Right: TAlgosimObject): Boolean; static; inline;
    class function Hasher(const Value: TAlgosimObject): Integer; static; inline;
    class function Comparer: IComparer<TAlgosimObject>; static;
    class function ValEqualityComparer: IEqualityComparer<TAlgosimObject>; static;
    class function RefEqualityComparer: IEqualityComparer<TAlgosimObject>; static;

    /// <summary>The copy constructor.</summary>
    constructor Create(AObject: TAlgosimObject); overload; virtual;

    class function ClassData: TAlgosimObjectClassData; inline;
    class function ClassFlags: TAlgosimObjectClassFlags; inline;

    /// <summary>A rough estimate of the memory size of the object, or 0 if not
    ///  implemented for this type of object.</summary>
    property MemorySize: UInt64 read GetMemorySize;

    /// <summary>Returns a textual representation of the data, if reasonable.
    ///  If so, the returned string is as accurate as possible. If not, a
    ///  textual summary of the contents is returned.</summary>
    function ToString: string; override;

    function ToInputString: string; virtual;

    function ToPreviewString: string; virtual;

    function ToSpeech: string; virtual;

    /// <summary>Returns a pretty-printed single-line representation of the
    ///  data.</summary>
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; virtual;

    /// <summary>Returns a pretty-printed multi-line representation of the
    ///  data.</summary>
    function GetAsMultilineText(const AOptions: TFormatOptions): string; virtual;

    /// <summary>Returns a pretty-printed, possibly multi-line representation of the
    ///  data, with optional annotations helping the user to understand the
    ///  value.</summary>
    function ExplainedOutput(const AOptions: TFormatOptions): string; virtual;

    /// <summary>Invokes the object, if applicable.</summary>
    procedure Invoke; virtual;

    /// <summary>Saves the data contained in the object in a file.</summary>
    /// <param name="AFileName">The file name of the created file.</param>
    procedure SaveToFile(const AFileName: string); overload; virtual;

    procedure SaveToFile(const AFileName: string; AOptions: TAlgosimStructure;
      AContext: TObject); overload; virtual;

    procedure SaveToFile(ADlgOwner: TComponent;
      const ADefFileName: string = ''); overload; virtual;

    /// <summary>Loads the object from a file.</summary>
    class function LoadFromFile(const AFileName: string;
      AEncoding: TEncoding = nil; const AParams: string = ''): TAlgosimObject; virtual;

    /// <summary>Copies the data contained in the object to the clipboard.</summary>
    procedure CopyToClipboard; virtual;

    /// <summary>The name of the AlgoSim data type of the object. Notice that
    ///  two objects of the same Delphi class might have different AlgoSim
    ///  data type names (e.g., typed structures).</summary>
    property TypeName: string read GetTypeName;

    /// <summary>The name of the AlgoSim data type of the object. This name
    ///  is potentially less informative than the <c>TypeName</c>; in particular,
    ///  two AlgoSim objects of the same Delphi class have the same
    ///  <c>ClassTypeName</c>.</summary>
    class function ClassTypeName: string; inline;

    /// <summary>Returns a clone of the current object, that is, a new AlgoSim
    ///  object of the same type with the same content as the current object.
    ///  </summary>
    /// <returns>A clone of the current object. The caller gains ownership of
    ///  this new object.</returns>
    function Clone: TAlgosimObject;

    /// <summary>Returns a reference to a subscripted object.</summary>
    /// <param name="ASubscript">The subscript to look up. Its objects are
    ///  not modified by the function.</param>
    /// <returns>If successful, a reference to the subscripted object. The
    ///  caller does not gain ownership of it.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the subscripted
    ///  object doesn't exist or can only be accessed by value.</exception>
    function GetSubscriptedRef(ASubscript: TSubscript): TAlgosimObject;

    /// <summary>Tries to return a reference to a subscripted object.</summary>
    /// <param name="ASubscript">The subscript to look up. Its objects are
    ///  not modified by the function.</param>
    /// <param name="AValue">If successful, becomes a reference to the
    ///  subscripted object. The caller does not gain ownership of it.</param>
    /// <returns>True iff a reference to the subscripted object could be
    ///  obtained.</returns>
    function TryGetSubscriptedRef(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; virtual;

    /// <summary>Returns a copy of a subscripted object.</summary>
    /// <param name="ASubscript">The subscript to look up. Its objects are
    ///  not modified by the function.</param>
    /// <returns>If successful, a copy of the subscripted object. The caller
    ///  gains ownership of it.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the subscripted
    ///  object doesn't exist.</exception>
    function GetSubscriptedValue(ASubscript: TSubscript): TAlgosimObject;

    /// <summary>Tries to return a copy of a subscripted object.</summary>
    /// <param name="ASubscript">The subscript to look up. Its objects are
    ///  not modified by the function.</param>
    /// <param name="AValue">If successful, is set to point to a copy of the
    ///  subscripted object. The caller gains ownership of the object.</param>
    /// <returns>True iff a copy of the subscripted object could be obtained.
    ///  </returns>
    function TryGetSubscriptedValue(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; virtual;

    /// <summary>Sets a subscripted member of the object.</summary>
    /// <param name="ASubscript">The subscript to look up. Its objects are not
    ///  modified by the function.</param>
    /// <param name="AValue">The value to assign to the subscripted member.
    ///  The current object gains ownership of this; hence, the caller
    ///  loses ownership of it.</param>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    procedure SetSubscript(ASubscript: TSubscript;
      AValue: TAlgosimObject); virtual;

    /// <summary>Returns an AlgoSim array containing all numbers found within
    ///  the object.</summary>
    /// <returns>The desired AlgoSim array. The caller gains ownership of this
    ///  object.</returns>
    function GetNumbers: TAlgosimArray;

    /// <summary>Returns the unary minus of the object, if applicable.</summary>
    /// <returns>The unary minus as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function UnaryMinus: TAlgosimObject; virtual;

    /// <summary>Returns the sum of all elements in the container, if
    ///  applicable. The elements may be numbers, vectors, or matrices. If the
    ///  container is empty and the elements are of unknown type, the elements
    ///  are assumed to be numbers and the empty sum 0 is returned.</summary>
    /// <returns>The desired sum as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_sum: TAlgosimNumericEntity; virtual;

    /// <summary>Returns the product of all elements in the container, if
    ///  applicable. The elements may be numbers or matrices. If the container
    ///  is empty and the elements are of unknown type, the elements are assumed
    ///  to be numbers and the empty product 1 is returned.</summary>
    /// <returns>The desired product as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_product: TAlgosimNumericEntity; virtual;

    /// <summary>Returns the arithmetic mean of all elements in the container,
    ///  if applicable. The elements may be numbers, vectors, or matrices. The
    ///  container must not be empty, or an exception is raised.</summary>
    /// <returns>The desired mean as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_ArithmeticMean: TAlgosimNumericEntity; virtual;

    /// <summary>Returns the geometric mean of all elements in the container,
    ///  if applicable. The elements must be numbers. The container must not
    ///  be empty, or an exception is raised.</summary>
    /// <returns>The desired mean as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_GeometricMean: TAlgosimNumber; virtual;

    /// <summary>Returns the harmonic mean of all elements in the container,
    ///  if applicable. The elements must be numbers. The container must not
    ///  be empty, or an exception is raised.</summary>
    /// <returns>The desired mean as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_HarmonicMean: TAlgosimNumber; virtual;

    /// <summary>Returns the largest number of all elements in the container,
    ///  if applicable. The elements must be real numbers. The container must
    ///  not be empty, or an exception is raised.</summary>
    /// <returns>The desired maximum as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_max: TAlgosimNumber; virtual;

    /// <summary>Returns the smallest number of all elements in the container,
    ///  if applicable. The elements must be real numbers. The container must
    ///  not be empty, or an exception is raised.</summary>
    /// <returns>The desired minimum as an AlgoSim object. The caller gains
    ///  ownership of this object.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported.</exception>
    function N_min: TAlgosimNumber; virtual;

    /// <summary>Returns the 1-based index of the first occurrence of a given
    ///  value in the current object, which has to be an indexed container.
    ///  </summary>
    /// <param name="AObj">The value to search for. This value is not modified
    ///  by the function.</param>
    /// <returns>The index of the first occurrence of the value, or ASO NULL if
    ///  it is not present.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function IndexOfValue(AObj: TAlgosimObject): TAlgosimObject; virtual;

    function IndexOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimObject; virtual;

    function Contains(AObj: TAlgosimObject): Boolean; inline;
    function ContainsEps(AObj: TAlgosimObject; const AEpsilon: TASR = 0): Boolean; inline;

    /// <summary>Returns an AlgoSim array containing the 1-based indices of the
    ///  subscripted members that equal a given value.</summary>
    /// <param name="AObj">The value to compare against. This object is not
    ///  modified by the function.</param>
    /// <returns>An AlgoSim array containing the indices of the matching
    ///  members. The caller gains ownership of this object.</returns>
    function IndicesOfValue(AObj: TAlgosimObject): TAlgosimArray; virtual;

    function IndicesOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimArray; virtual;

    function CountValue(AObj: TAlgosimObject): Integer;
    function CountValueEps(AObj: TAlgosimObject; const AEpsilon: TASR = 0): Integer;

    /// <summary>Returns an AlgoSim array containing the 1-based indices of the
    ///  subscripted members that satisfy a given predicate.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  subscripted members.</param>
    /// <returns>An AlgoSim array containing the indices of the matching
    ///  members. The caller gains ownership of this object.</returns>
    function IndicesOf(APredicate: TASOPredicate): TAlgosimArray; virtual;

    /// <summary>Returns the count of the subscripted members that satisfy
    ///  a given predicate.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  subscripted members.</param>
    /// <returns>The count of matching members.</returns>
    function Count(APredicate: TASOPredicate): Integer; virtual;

    /// <summary>Tests whether a given predicate is satisfied by all subscripted
    ///  members of the object.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  subscripted members.</param>
    /// <returns>True iff all subscripted members satisfy the predicate.
    ///  </returns>
    function ForAll(APredicate: TASOPredicate): Boolean; virtual;

    /// <summary>Tests whether there exists a subscripted member that satisfies
    ///  a given predicate.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  subscripted members.</param>
    /// <returns>True iff there exists a subscripted member that satisfies the
    ///  predicate.</returns>
    function Exists(APredicate: TASOPredicate): Boolean; virtual;

    /// <summary>Tests whether there exists exactly one subscripted member that
    ///  satisfies a given predicate.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  subscripted members.</param>
    /// <returns>True iff there exists a unique subscripted member that
    ///  satisfies the predicate.</returns>
    function ExistsUnique(APredicate: TASOPredicate): Boolean; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  object, consisting of all subscripted members of the current object
    ///  that satisfy a given predicate.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  subscripted members.</param>
    /// <returns>A new AlgoSim object containing (copies of) the matching
    ///  elements.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function Filter(APredicate: TASOPredicate): TAlgosimObject; virtual;

    /// <summary>Returns an array consisting of all subscripted members of the
    ///  current object that satisfy a given predicate.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  subscripted members.</param>
    /// <returns>A new AlgoSim array containing (copies of) the matching
    ///  elements.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function Pick(APredicate: TASOPredicate; ALevel: Integer = 1): TAlgosimArray;

    /// <summary>Returns an array consisting of all recursively contained
    ///  members of the current object that satisfy a given predicate.</summary>
    /// <param name="APredicate">The predicate to use when testing the
    ///  members.</param>
    /// <returns>A new AlgoSim array containing (copies of) the matching
    ///  elements.</returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function PickRecursive(APredicate: TASOPredicate): TAlgosimArray; virtual;

    /// <summary>Applies a function to each member in the container, or to each
    ///  member satisfying a specified predicate, if applicable.</summary>
    /// <param name="AFunction">The function to apply to the members.</param>
    /// <param name="APredicate">A predicate used to test the members; only
    ///  members satisfying the predicate will be touched. If <c>nil</c>, the
    ///  behaviour is as if the predicate is identically <c>True</c>.</param>
    /// <param name="ALevel">The level at which the function is applied. If
    ///  <c>ALevel = 1</c> then the function is applied to the members of the
    ///  object, if <c>ALevel = 2</c> then the function is applied to the
    ///  members of the object's members, and so on.</param>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); virtual;

    /// <summary>Replaces each member satisfying the given predicate with
    ///  (copies) of the given object.</summary>
    /// <param name="APredicate">The predicate to use when testing members. If
    ///  <c>nil</c>, the behaviour is as if the predicate is identically
    ///  <c>True</c>.</param>
    /// <param name="ANewValue">The value to replace matching members with.
    ///  This object isn't modified.</param>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); overload; virtual;

    /// <summary>Replaces each member equal to a given object with a copy of a
    ///  different object.</summary>
    /// <param name="AOldValue">The value to compare against. This object isn't
    ///  modified.</param>
    /// <param name="ANewValue">The value to replace matching members with. This
    ///  object isn't modified.</param>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    procedure Replace(AOldValue, ANewValue: TAlgosimObject;
      ALevel: Integer = 1); overload;

    procedure Replace(ANewValue: TAlgosimObject; ALevel: Integer = 1); overload;

    procedure RemoveIf(APredicate: TASOPredicate; ALevel: Integer = 1);

    procedure RemoveAll(AOldValue: TAlgosimObject; ALevel: Integer = 1);

    /// <summary>Accumulates the values in the container based on a user-
    ///  specified accumulation function and a user-defined start value.</summary>
    /// <param name="AInitialValue">The initial value for the accumulation.
    ///  This value is not modified by the function.</param>
    /// <param name="AFunction">The accumulation function to use.</param>
    /// <returns>The accumulated value. The caller gains ownership of this
    ///  object.</returns>
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; virtual;

    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; virtual;

    function AccumulateSteps(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; virtual;

    /// <summary>Removes the first member(s) in the container, if applicable.</summary>
    procedure RemoveFirst(N: Integer = 1); virtual;

    /// <summary><c>True</c> iff the object is an 'object container', that is,
    ///  if it is made up of a collection of other AlgoSim objects and also
    ///  supports the 'container' interface.</summary>
    /// <remarks>Must not raise (noexcept).</remarks>
    class function IsObjectContainer: Boolean; inline;

    /// <summary><c>True</c> iff the object is a 'container' and the elements
    ///  have a well-defined order.</summary>
    /// <remarks>Must not raise (noexcept).</remarks>
    class function IsOrderedContainer: Boolean; inline;

    /// <summary>The AlgoSim objects that this object contains.
    ///  This property can be used iff the object is an object container, that
    ///  is, iff <c>IsObjectContainer</c> is <c>True</c>.</summary>
    /// <remarks>On reading, the obtained object SHOULD be considered read-only.
    ///  On writing, the current object gains ownership of the given object,
    ///  even if the operation raises an exception. Any previous member at the
    ///  same index is automatically freed. The property is using 1-based
    ///  indices.</remarks>
    property Elements[Index: Integer]: TAlgosimObject read GetElement write SetElement;

    /// <summary>Returns the number of contained elements in <c>Elements</c>.
    ///  This property can be used iff the object is an object container, that
    ///  is, iff <c>IsObjectContainer</c> is <c>True</c>.</summary>
    property ElementCount: Integer read GetElementCount;

    /// <summary>Adds an element to this container.
    ///  This property can be used iff the object is an object container, that
    ///  is, iff <c>IsObjectContainer</c> is <c>True</c>.</summary>
    /// <returns>Some type of containers will only conditionally add the element.
    ///  If it is not added, it is freed. These containers will return True iff
    ///  the element is actually added. The typical example is a set told to add
    ///  an already existing element.</returns>
    /// <remarks>The current object gains ownership of the given object,
    ///  even if the operation raises an exception or returns False.</remarks>
    function AddElement(const AElement: TAlgosimObject): Boolean; virtual;

    function ElementsAre(AASOMetaclass: TAlgosimObjectClass): Boolean;

    function HasElementOfClass(AASOMetaclass: TAlgosimObjectClass): Boolean;

    /// <summary>For container-like objects that support this concept, reads or
    ///  sets the capacity. For other types of objects, this value is not used.
    ///  </summary>
    property Capacity: Integer read GetCapacity write SetCapacity;

    /// <summary>For container-like objects that support the copcept of a
    ///  'capacity', sets the capacity to the actual count of elements. For
    ///  other types of objects, this method has no effect.</summary>
    procedure TrimExcess; virtual;

    /// <summary><c>True</c> iff the object supports the property and considers
    ///  itself to be of a complex type (as opposed to a real type).</summary>
    /// <remarks>For instance, a real number, vector, or matrix has
    //   <c>IsComplex = False</c> while a complex number, vector, or matrix has
    ///  <c>IsComplex = True</c>. A container has <c>IsComplex = True</c> iff
    ///  any of its members has <c>IsComplex = True</c>.</remarks>
    property IsComplex: Boolean read GetIsComplex;

    /// <summary><c>True</c> iff the object is a 'value container', that is, if
    ///  it naturally is made up of a collection of values that easily can be
    ///  converted into AlgoSim objects and also supports the 'value container'
    ///  interface.</summary>
    /// <remarks>Must not raise (noexcept).</remarks>
    class function IsValueContainer: Boolean; inline;

    /// <summary><c>True</c> iff the object is an object or a value container.
    ///  </summary>
    /// <remarks>Must not raise (noexcept).</remarks>
    class function IsContainer: Boolean; inline;

    /// <summary>The AlgoSim objects that this object implicitly contains.
    ///  This property can be used iff the object is an object or a value
    ///  container, that is, iff <c>IsContainer</c> is <c>True</c>.</summary>
    /// <remarks>On reading, the caller gains ownership of the given object and
    ///  SHOULD free it when it no longer needs it.
    ///  On writing, the current object gains ownership of the given object,
    ///  even if the operation raises an exception. The property is using
    ///  1-based indices.</remarks>
    property Values[Index: Integer]: TAlgosimObject read GetValue write SetValue;

    /// <summary>Returns the number of values in <c>Values</c>.
    ///  This property can be used iff the object is an object or a value
    ///  container, that is, iff <c>IsContainer</c> is <c>True</c>.</summary>
    property ValueCount: Integer read GetValueCount;

    /// <summary><c>True</c> iff the object is a container or value container
    ///  that is able to index its values using points (x, y) of integers
    ///  (e.g., a matrix, a table, or a pixmap).</summary>
    /// <remarks>Must not raise (noexcept).</remarks>
    class function IsPlanarContainer: Boolean; inline;

    /// <summary><c>True</c> iff the object is a value container that is able
    ///  to index its values using points (x, y) of integers (e.g., a matrix,
    ///  a table, or a pixmap).</summary>
    /// <remarks>Must not raise (noexcept).</remarks>
    class function IsPlanarValueContainer: Boolean; inline;

    /// <summary>The AlgoSim objects that this object implicitly contains.
    ///  This property can be used iff the object is a planar value container,
    ///  that is, iff <c>IsPlanarValueContainer</c> is <c>True</c>.</summary>
    /// <remarks>On reading, the caller gains ownership of the given object and
    ///  SHOULD free it when it no longer needs it. On writing, the current
    ///  object gains ownership of the given object, even if the operation
    ///  raises an exception. The indices are 1-based.</remarks>
    property ValueFromPoint[const Index: TPoint]: TAlgosimObject read GetValueFromPoint write SetValueFromPoint;

    /// <summary>The width and height of the object, if applicable.
    ///  For objects that don't have a planar extent, 1×1 is returned.</summary>
    property PlanarExtent: TSize read GetPlanarExtent write SetPlanarExtent;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  object, containing (copies of) the first <c>N</c> members of the
    ///  current object, if applicable.</summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function First(N: Integer): TAlgosimObject; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  object, containing (copies of) the last <c>N</c> members of the
    ///  current object, if applicable.</summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function Last(N: Integer): TAlgosimObject; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  object, containing (copies of) the members of the current object
    ///  with indices in [A, B], if applicable. The indices are 1-based.</summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function Part(A, B: Integer): TAlgosimObject; overload; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  object, containing (copies of) the members of the current object
    ///  with indices in [A, \infty), if applicable. The indices are 1-based.
    ///  </summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function Part(A: Integer): TAlgosimObject; overload; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  object, containing (copies of) the members of the current object
    ///  with the specified indices, if applicable. The indices are 1-based.
    ///  </summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object or if any index is out of bounds.
    ///  </exception>
    /// <remarks>The current object is not modified.</remarks>
    function Part(const ARanges: array of TRange): TAlgosimObject; overload; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  object, containing (copies of) the members of the current object
    ///  with the specified indices, if applicable. The indices are 1-based.
    ///  </summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object or if any index is out of bounds.
    ///  </exception>
    /// <remarks>The current object is not modified.</remarks>
    function Part(const AIndices: array of Integer): TAlgosimObject; overload; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  planar container object, containing (copies of) the members of the
    ///  current object with the specified indices, if applicable. The indices
    ///  are 1-based.</summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object or if any index is out of bounds.
    ///  </exception>
    /// <remarks>The current object is not modified.</remarks>
    function Part2d(const ARangesX, ARangesY: array of TRange): TAlgosimObject; overload; virtual;

    /// <summary>Returns an AlgoSim object of the same type as the current
    ///  planar container object, containing (copies of) the members of the
    ///  current object with the specified indices, if applicable. The indices
    ///  are 1-based.</summary>
    /// <returns>A new AlgoSim object. The caller gains ownership of this.
    ///  </returns>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object or if any index is out of bounds.
    ///  </exception>
    /// <remarks>The current object is not modified.</remarks>
    function Part2d(const AIndicesX, AIndicesY: array of Integer): TAlgosimObject; overload; virtual;

    function Row(const AIndex: Integer): TAlgosimObject; inline;
    function Column(const AIndex: Integer): TAlgosimObject; inline;

    function Rows: TAlgosimArray;
    function Columns: TAlgosimArray;

    function Random: TAlgosimObject; virtual;

    /// <summary>Compares two AlgoSim objects for (strict) equality of their
    ///  data.</summary>
    /// <param name="Obj">The object to compare to.</param>
    /// <returns>True iff the data of the current object is identical to the
    ///  data of <c>Obj</c>.</returns>
    function Equals(Obj: TObject): Boolean; override;

    function GetHashCode: Integer; override;

    class function SortClass: TSortClass; virtual;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; virtual;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; virtual;
    function SortClassGetHashCode: Integer; virtual;

    procedure Sort; overload; virtual;
    procedure Sort(AComparer: IComparer<TAlgosimObject>); overload; virtual;
    procedure Sort(AComparer: IComparer<TASR>); overload; virtual;
    procedure Sort(AComparer: IComparer<TASC>); overload; virtual;

    procedure Shuffle; virtual;
    procedure Reverse; virtual;

    function RemoveDuplicates: TAlgosimObject; virtual;
    function RemoveDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; virtual;
    function RemoveAdjacentDuplicates: TAlgosimObject; virtual;
    function RemoveAdjacentDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; virtual;

    function Frequencies: TAlgosimArray; virtual;
    function FrequenciesEps(const Epsilon: TASR = 0): TAlgosimArray; virtual;
    function CollapseSequences: TAlgosimArray; virtual;
    function CollapseSequencesEps(const Epsilon: TASR = 0): TAlgosimArray; virtual;

    function RotLeft(N: Integer): TAlgosimObject; virtual;
    function RotRight(N: Integer): TAlgosimObject; virtual;

    procedure Append(AElement: TAlgosimObject); virtual;
    procedure ExtendWith(AElement: TAlgosimObject); virtual;
    procedure Insert(AIndex: Integer; AElement: TAlgosimObject); virtual;
    procedure Remove(const AIndices: array of Integer); overload; virtual;
    procedure Remove(const ARanges: array of TRange); overload;
    procedure Truncate(ANewLength: Integer); virtual;
    procedure Swap(Index1, Index2: Integer); virtual;

    function WithSpecificValues(AValues: TAlgosimArray): TAlgosimObject; virtual;

    /// <summary>Creates an integer with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToInteger: TASI; virtual;

    /// <summary>Creates a rational number with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToRationalNumber: TRationalNumber; virtual;

    /// <summary>Creates a real number with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToRealNumber: TASR; virtual;

    /// <summary>Creates a complex number with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToComplexNumber: TASC; virtual;

    /// <summary>Creates a number object with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToNumber: TAlgosimObject; virtual;

    /// <summary>Creates a real vector with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToRealVector: TRealVector; virtual;

    /// <summary>Creates a complex vector with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToComplexVector: TComplexVector; virtual;

    /// <summary>Creates a vector object with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToVector: TAlgosimVector; virtual;

    /// <summary>Creates a real matrix with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToRealMatrix: TRealMatrix; virtual;

    /// <summary>Creates a complex matrix with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToComplexMatrix: TComplexMatrix; virtual;

    /// <summary>Creates a matrix object with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToMatrix: TAlgosimMatrix; virtual;

    // The following As* methods work like the corresponding To* methods
    // but return a reference to the original data instead of copying it to a
    // new buffer, if possible. Hence, changing the returned values of the As*
    // methods might change the original objects. (But if that isn't a problem,
    // the As* methods might return faster, since they don't need to copy a
    // potentially large amount of data.)
    function AsRealVector: TRealVector; virtual;
    function AsComplexVector: TComplexVector; virtual;
    function AsVector: TAlgosimVector; inline;
    function AsRealMatrix: TRealMatrix; virtual;
    function AsComplexMatrix: TComplexMatrix; virtual;
    function AsMatrix: TAlgosimMatrix;

    function ToCharacter: Char; virtual;

    /// <summary>Creates a boolean value with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToBoolean: Boolean; virtual;

    /// <summary>Creates an AlgoSim array object with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToList: TAlgosimArray; virtual;

    /// <summary>Creates an AlgoSim table object with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToTable: TASTable; virtual;

    /// <summary>Creates an AlgoSim set object with the same information as the
    ///  current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToSet: TAlgosimSet; virtual;

    /// <summary>Creates an AlgoSim binary object with the same information as
    ///  the current object, if possible.</summary>
    /// <exception cref="EAlgosimObjectException">Raised if the operation is not
    ///  supported by this type of object.</exception>
    /// <remarks>The current object is not modified.</remarks>
    function ToBinaryObject: TAlgosimBinaryData; virtual;

    /// <summary>Tries to convert the object's value to a TASI integer.</summary>
    /// <param name="ASI">If the function returns <c>true</c>, this value is set
    ///  to the number represented by the object's value.</param>
    /// <returns>Returns <c>true</c> iff the object is a number that can be
    ///  exactly represented as a TASI.</returns>
    function TryToASI(out ASI: TASI): Boolean; virtual;

    /// <summary>Tries to convert the object's value to a rational number.</summary>
    /// <param name="R">If the function returns <c>true</c>, this value is set
    ///  to the number represented by the object's value.</param>
    /// <returns>Returns <c>true</c> iff the object is a number that can be
    ///  exactly represented as a rational number.</returns>
    function TryToRat(out R: TRationalNumber): Boolean; virtual;

    /// <summary>Tries to convert the object's value to a 32-bit signed
    ///  integer.</summary>
    /// <param name="Int">If the function returns <c>true</c>, this value is set
    ///  to the number represented by the object's value.</param>
    /// <returns>Returns <c>true</c> iff the object is a number that can be
    ///  exactly represented as a 32-bit signed integer.</returns>
    function TryToInt32(out Int: Int32): Boolean; virtual;

    /// <summary>Tries to convert the object's value to a 64-bit signed
    ///  integer.</summary>
    /// <param name="Int">If the function returns <c>true</c>, this value is set
    ///  to the number represented by the object's value.</param>
    /// <returns>Returns <c>true</c> iff the object is a number that can be
    ///  exactly represented as a 64-bit signed integer.</returns>
    function TryToInt64(out Int: Int64): Boolean; virtual;

    /// <summary>Tries to convert the object's value to a floating-point number.
    ///  </summary>
    /// <param name="Int">If the function returns <c>true</c>, this value is set
    ///  to the number represented by the object's value.</param>
    /// <returns>Returns <c>true</c> iff the object is a number that can be
    ///  represented as a floating-point number.</returns>
    function TryToASR(out Val: TASR): Boolean; virtual;

    /// <summary>Tries to convert the object's value to complex number.
    ///  </summary>
    /// <param name="Int">If the function returns <c>true</c>, this value is set
    ///  to the number represented by the object's value.</param>
    /// <returns>Returns <c>true</c> iff the object is a number that can be
    ///  represented as a floating-point complex number.</returns>
    function TryToASC(out Val: TASC): Boolean; virtual;

    function IsASI: Boolean; inline;
    function IsRat: Boolean; inline;
    function IsInt32: Boolean; inline;
    function IsInt64: Boolean; inline;
    function IsASR: Boolean; inline;
    function IsASC: Boolean; inline;

    function ToASI: TASI; inline;
    function ToRat: TRationalNumber; inline;
    function ToInt32: Int32; inline;
    function ToInt64: Int64; inline;
    function ToASR: TASR; inline;
    function ToASC: TASC; inline;

    /// <summary>If possible, returns a pointer (and an associated byte length
    ///  to the raw, binary data of the object.</summary>
    /// <param name="Buf">If the function returns <c>true</c>, receives the
    ///  pointer to the raw, binary data of the object.</param>
    /// <param name="Len">If the function returns <c>true</c>, receives the
    ///  length of the binary data of the object.</param>
    /// <returns><c>True</c> iff it is possible to obtain a read-only pointer
    ///  to the binary data of the object.</returns>
    /// <remarks>The binary data pointed to by <c>Buf</c> must be considered
    ///  read-only by the caller; it must not be modified in any way. The
    ///  typical reason why this function returns <c>false</c> is that the
    ///  object's data isn't stored as a contiguous sequence of bytes in memory.
    ///  </remarks>
    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; virtual;

    /// <summary>Sets the binary data of the object using a provided buffer,
    ///  if supported by the object type.</summary>
    /// <param name="Buf">The buffer to copy bytes from. This is not modified
    ///  by the procedure.</param>
    /// <param name="Len">The size of the buffer, in bytes.</param>
    /// <exception cref="EAlgosimObjectException">Raised if the object doesn't
    ///  support having its data set from a byte buffer or if the byte buffer
    ///  is invalid for the object type (either in size or in content).
    ///  </exception>
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); overload; virtual;
    procedure SetBinaryData(const AData: array of Byte); overload;

    function ToColor: TRGB; virtual;
    function ToPixel: TASPixel; virtual;

    property MaxLen: Integer read GetMaxLen write SetMaxLen;

  end;

  [AlgosimObject('null')]
  TAlgosimNullObject = class(TAlgosimObject)
  public
    constructor Create(AObject: TAlgosimObject); override;
    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function ToBoolean: Boolean; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
    function Equals(Obj: TObject): Boolean; override;
    function ToInputString: string; override;
  end;

  TNormType = (ntEuclidean, ntFrobenius, ntPNorm, ntMaxNorm, ntSumNorm, ntKNorm,
    ntMaxColSum, ntMaxRowSum, ntSpectral);

  TAlgosimInteger = class;
  TAlgosimRationalNumber = class;
  TAlgosimRealNumber = class;
  TAlgosimComplexNumber = class;

  [AlgosimObject('numeric entity')]
  TAlgosimNumericEntity = class abstract(TAlgosimObject)
  strict private
    var
      FFormatCode: UInt64;
    // 00000000 00000000 00000000 00000000
    //          LLLLLLLL      fFF gGGGGGGG
    // 00000000 00000000 00000000 00000000
    // SSSSSSSS eEBBBBBB dDDDDDDD DDDDDDDD
    const
      FCM_DIGITS   = $0000000000007FFF;
      FCM_DIGITSO  = $0000000000008000;
      FCM_BASE     = $00000000003F0000;
      FCM_EXPFMT   = $0000000000400000;
      FCM_EXPFMTO  = $0000000000800000;
      FCM_STYLE    = $00000000FF000000;
      FCM_GROUP    = $0000007F00000000;
      FCM_GROUPO   = $0000008000000000;
      FCM_NUMFMT   = $0000030000000000;
      FCM_NUMFMTO  = $0000040000000000;
      FCM_MINLEN   = $00FF000000000000;
    function GetNumDigits: Integer; inline;
    procedure SetNumDigits(const Value: Integer); inline;
    function GetNumDigitsOverride: Boolean; inline;
    procedure SetNumDigitsOverride(const Value: Boolean); inline;
    function GetStyle: TFormatStyle; inline;
    procedure SetStyle(const Value: TFormatStyle); inline;
    function GetNumberBase: Integer; inline;
    procedure SetNumberBase(Value: Integer); inline;
    function GetDigitGrouping: Integer; inline;
    procedure SetDigitGrouping(Value: Integer); inline;
    function GetDigitGroupingOverride: Boolean; inline;
    procedure SetDigitGroupingOverride(Value: Boolean); inline;
    function GetNumberFormat: TNumberFormat; inline;
    procedure SetNumberFormat(Value: TNumberFormat); inline;
    function GetNumberFormatOverride: Boolean; inline;
    procedure SetNumberFormatOverride(Value: Boolean); inline;
    function GetPrettyExp: Boolean; inline;
    procedure SetPrettyExp(Value: Boolean); inline;
    function GetPrettyExpOverride: Boolean; inline;
    procedure SetPrettyExpOverride(Value: Boolean); inline;
    function GetMinLength: Integer; inline;
    procedure SetMinLength(Value: Integer); inline;
  protected
    function ApplyOptions(const AOptions: TFormatOptions): TFormatOptions;
  public
    property FormatCode: UInt64 read FFormatCode write FFormatCode;
    property NumDigits: Integer read GetNumDigits write SetNumDigits;
    property NumDigitsOverride: Boolean read GetNumDigitsOverride write SetNumDigitsOverride;
    property Style: TFormatStyle read GetStyle write SetStyle;
    property NumberBase: Integer read GetNumberBase write SetNumberBase;
    property DigitGrouping: Integer read GetDigitGrouping write SetDigitGrouping;
    property DigitGroupingOverride: Boolean read GetDigitGroupingOverride write SetDigitGroupingOverride;
    property NumberFormat: TNumberFormat read GetNumberFormat write SetNumberFormat;
    property NumberFormatOverride: Boolean read GetNumberFormatOverride write SetNumberFormatOverride;
    property PrettyExp: Boolean read GetPrettyExp write SetPrettyExp;
    property PrettyExpOverride: Boolean read GetPrettyExpOverride write SetPrettyExpOverride;
    property MinLength: Integer read GetMinLength write SetMinLength;

    function RealPart: TAlgosimNumericEntity; virtual;
    function ImaginaryPart: TAlgosimNumericEntity; virtual;
    function Abs: TAlgosimNumericEntity; virtual;
    function Square: TAlgosimNumericEntity; virtual;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; virtual;
    function NormSquared: TAlgosimRealNumber; virtual;
    function Inverse: TAlgosimNumericEntity; virtual;
    function Transpose: TAlgosimMatrix; virtual;
    function ConjugateTranspose: TAlgosimMatrix; virtual;

    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; virtual;

    function IsPositive(const Eps: Double = 0): Boolean; virtual;
    function IsNonNegative(const Eps: Double = 0): Boolean; virtual;
    function IsNegative(const Eps: Double = 0): Boolean; virtual;
    function IsNonPositive(const Eps: Double = 0): Boolean; virtual;
    function IsZero(const Eps: Double = 0): Boolean; virtual;
    function IsNonZero(const Eps: Double = 0): Boolean; virtual;

    procedure Defuzz(const Eps: Double = 1E-8); virtual;
  end;

  TSDDKind = (
    sddLt,      // x < a
    sddLeq,     // x <= a
    sddGt,      // x > a
    sddGeq,     // x >= a
    sddBii,     // a <= x <= b
    sddBei,     // a < x <= b
    sddBie,     // a <= x < b
    sddBee      // a < x < b
    );

  TSimpleDomainDescription = record
    a, b: TASR;
    Kind: TSDDKind;
    Complement: Boolean;
    function Contains(const x: TASR): Boolean;
  end;

  TSDD = TSimpleDomainDescription;

  [AlgosimObject('number')]
  TAlgosimNumber = class abstract(TAlgosimNumericEntity)
  protected
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;

    function AddASR(ASR: TAlgosimRealNumber): TAlgosimNumber; virtual; abstract;
    function AddASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; virtual; abstract;
    function AddASI(ASI: TAlgosimInteger): TAlgosimNumber; virtual; abstract;
    function AddRat(R: TAlgosimRationalNumber): TAlgosimNumber; virtual; abstract;
    function AddTo(ANum: TAlgosimNumber): TAlgosimNumber; virtual; abstract;

    function SubtractASR(ASR: TAlgosimRealNumber): TAlgosimNumber; virtual; abstract;
    function SubtractASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; virtual; abstract;
    function SubtractASI(ASI: TAlgosimInteger): TAlgosimNumber; virtual; abstract;
    function SubtractRat(R: TAlgosimRationalNumber): TAlgosimNumber; virtual; abstract;
    function SubtractFrom(ANum: TAlgosimNumber): TAlgosimNumber; virtual; abstract;

    function MultiplyASR(ASR: TAlgosimRealNumber): TAlgosimNumber; virtual; abstract;
    function MultiplyASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; virtual; abstract;
    function MultiplyASI(ASI: TAlgosimInteger): TAlgosimNumber; virtual; abstract;
    function MultiplyRat(R: TAlgosimRationalNumber): TAlgosimNumber; virtual; abstract;
    function MultiplyTo(ANum: TAlgosimNumber): TAlgosimNumber; virtual; abstract;

    function DivideASR(ASR: TAlgosimRealNumber): TAlgosimNumber; virtual; abstract;
    function DivideASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; virtual; abstract;
    function DivideASI(ASI: TAlgosimInteger): TAlgosimNumber; virtual; abstract;
    function DivideRat(R: TAlgosimRationalNumber): TAlgosimNumber; virtual; abstract;
    function DivideBy(ANum: TAlgosimNumber): TAlgosimNumber; virtual; abstract;

    function RaiseToASR(ASR: TAlgosimRealNumber): TAlgosimNumber; virtual; abstract;
    function RaiseToASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; virtual; abstract;
    function RaiseToASI(ASI: TAlgosimInteger): TAlgosimNumber; virtual; abstract;
    function RaiseToRat(R: TAlgosimRationalNumber): TAlgosimNumber; virtual; abstract;
    function RaiseTo(ANum: TAlgosimNumber): TAlgosimNumber; virtual; abstract;

    function GetMaxLen: Integer; override;
    procedure SetMaxLen(AValue: Integer); override;

  public
    function Conjugate: TAlgosimNumber; virtual; abstract;
    function Argument: TAlgosimRealNumber; virtual; abstract;

    function ComputeFunction(const ARealDomain: TSDD; ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; overload; virtual; abstract;
    function ComputeFunction(ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; overload; virtual; abstract;

    procedure Increase(AAmount: TASI = 1); virtual; abstract;

    class function Add(Left, Right: TAlgosimNumber): TAlgosimNumber;
    class function Subtract(Left, Right: TAlgosimNumber): TAlgosimNumber;
    class function Multiply(Left, Right: TAlgosimNumber): TAlgosimNumber;
    class function Divide(Left, Right: TAlgosimNumber): TAlgosimNumber;
    class function Power(Left, Right: TAlgosimNumber): TAlgosimNumber;

    class function LessThan(Left, Right: TAlgosimNumber): Boolean;
    class function LessThanOrEqualTo(Left, Right: TAlgosimNumber): Boolean;
    class function GreaterThan(Left, Right: TAlgosimNumber): Boolean;
    class function GreaterThanOrEqualTo(Left, Right: TAlgosimNumber): Boolean;

    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;

    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;

    function AsMemberOfSimplestField: TAlgosimNumber; virtual; abstract;

    function ToColor: TRGB; override;
  end;

  [AlgosimObject('integer')]
  TAlgosimInteger = class(TAlgosimNumber)
  protected
    FValue: TASI;

    function AddASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function AddASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function AddASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function AddRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function AddTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function SubtractASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function SubtractASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function SubtractASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function SubtractRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function SubtractFrom(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function MultiplyASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function MultiplyASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function MultiplyASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function MultiplyRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function MultiplyTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function DivideASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function DivideASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function DivideASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function DivideRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function DivideBy(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function RaiseToASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function RaiseToASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function RaiseToASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function RaiseToRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function RaiseTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function GetMemorySize: UInt64; override;

  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TASI);
    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function ExplainedOutput(const AOptions: TFormatOptions): string; override;
    function AsMemberOfSimplestField: TAlgosimNumber; override;
    property Value: TASI read FValue write FValue;
    function UnaryMinus: TAlgosimObject; override;
    function Conjugate: TAlgosimNumber; override;
    function Argument: TAlgosimRealNumber; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function Inverse: TAlgosimNumericEntity; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;
    function IsPositive(const Eps: Double = 0): Boolean; override;
    function IsNonNegative(const Eps: Double = 0): Boolean; override;
    function IsNegative(const Eps: Double = 0): Boolean; override;
    function IsNonPositive(const Eps: Double = 0): Boolean; override;
    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;
    function ComputeFunction(const ARealDomain: TSDD; ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ComputeFunction(ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ToRealNumber: TASR; override;
    function ToComplexNumber: TASC; override;
    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;
    function ToBoolean: Boolean; override;
    function TryToASI(out ASI: Int64): Boolean; override;
    function TryToRat(out R: TRationalNumber): Boolean; override;
    function TryToInt32(out Int: Integer): Boolean; override;
    function TryToInt64(out Int: Int64): Boolean; override;
    function TryToASR(out Val: TASR): Boolean; override;
    function TryToASC(out Val: TASC): Boolean; override;
    procedure Increase(AAmount: TASI = 1); override;

    function Equals(Obj: TObject): Boolean; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;
  end;

  [AlgosimObject('rational number')]
  TAlgosimRationalNumber = class(TAlgosimNumber)
  protected
    FValue: TRationalNumber;

    function AddASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function AddASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function AddASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function AddRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function AddTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function SubtractASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function SubtractASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function SubtractASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function SubtractRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function SubtractFrom(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function MultiplyASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function MultiplyASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function MultiplyASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function MultiplyRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function MultiplyTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function DivideASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function DivideASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function DivideASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function DivideRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function DivideBy(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function RaiseToASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function RaiseToASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function RaiseToASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function RaiseToRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function RaiseTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function GetMemorySize: UInt64; override;

  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TRationalNumber);
    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function AsMemberOfSimplestField: TAlgosimNumber; override;
    function ExplainedOutput(const AOptions: TFormatOptions): string; override;
    property Value: TRationalNumber read FValue write FValue;
    function UnaryMinus: TAlgosimObject; override;
    function Conjugate: TAlgosimNumber; override;
    function Argument: TAlgosimRealNumber; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function Inverse: TAlgosimNumericEntity; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;
    function IsPositive(const Eps: Double = 0): Boolean; override;
    function IsNonNegative(const Eps: Double = 0): Boolean; override;
    function IsNegative(const Eps: Double = 0): Boolean; override;
    function IsNonPositive(const Eps: Double = 0): Boolean; override;
    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;
    function ComputeFunction(const ARealDomain: TSDD; ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ComputeFunction(ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ToRealNumber: TASR; override;
    function ToComplexNumber: TASC; override;
    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;
    function ToBoolean: Boolean; override;
    function TryToASI(out ASI: Int64): Boolean; override;
    function TryToRat(out R: TRationalNumber): Boolean; override;
    function TryToInt32(out Int: Integer): Boolean; override;
    function TryToInt64(out Int: Int64): Boolean; override;
    function TryToASR(out Val: TASR): Boolean; override;
    function TryToASC(out Val: TASC): Boolean; override;
    procedure Increase(AAmount: TASI = 1); override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;
  end;

  [AlgosimObject('real number')]
  TAlgosimRealNumber = class(TAlgosimNumber)
  protected

    FValue: TASR;

    function AddASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function AddASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function AddASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function AddRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function AddTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function SubtractASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function SubtractASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function SubtractASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function SubtractRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function SubtractFrom(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function MultiplyASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function MultiplyASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function MultiplyASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function MultiplyRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function MultiplyTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function DivideASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function DivideASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function DivideASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function DivideRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function DivideBy(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function RaiseToASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function RaiseToASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function RaiseToASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function RaiseToRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function RaiseTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function GetMemorySize: UInt64; override;

  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TASR);
    function ToString: string; override;
    function ToSpeech: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function AsMemberOfSimplestField: TAlgosimNumber; override;
    function ExplainedOutput(const AOptions: TFormatOptions): string; override;
    property Value: TASR read FValue write FValue;
    function UnaryMinus: TAlgosimObject; override;
    function Conjugate: TAlgosimNumber; override;
    function Argument: TAlgosimRealNumber; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function Inverse: TAlgosimNumericEntity; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;
    function IsPositive(const Eps: Double = 0): Boolean; override;
    function IsNonNegative(const Eps: Double = 0): Boolean; override;
    function IsNegative(const Eps: Double = 0): Boolean; override;
    function IsNonPositive(const Eps: Double = 0): Boolean; override;
    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;
    procedure Defuzz(const Eps: Double = 1E-8); override;
    function ComputeFunction(const ARealDomain: TSDD; ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ComputeFunction(ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ToRealNumber: TASR; override;
    function ToComplexNumber: TASC; override;
    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;
    function ToBoolean: Boolean; override;
    function TryToASI(out ASI: Int64): Boolean; override;
    function TryToRat(out R: TRationalNumber): Boolean; override;
    function TryToInt32(out Int: Integer): Boolean; override;
    function TryToInt64(out Int: Int64): Boolean; override;
    function TryToASR(out Val: TASR): Boolean; override;
    function TryToASC(out Val: TASC): Boolean; override;
    procedure Increase(AAmount: TASI = 1); override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;
  end;

  [AlgosimObject('complex number', [asoComplex])]
  TAlgosimComplexNumber = class(TAlgosimNumber)
  protected

    FValue: TASC;

    function AddASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function AddASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function AddASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function AddRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function AddTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function SubtractASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function SubtractASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function SubtractASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function SubtractRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function SubtractFrom(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function MultiplyASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function MultiplyASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function MultiplyASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function MultiplyRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function MultiplyTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function DivideASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function DivideASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function DivideASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function DivideRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function DivideBy(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function RaiseToASR(ASR: TAlgosimRealNumber): TAlgosimNumber; override;
    function RaiseToASC(ASC: TAlgosimComplexNumber): TAlgosimNumber; override;
    function RaiseToASI(ASI: TAlgosimInteger): TAlgosimNumber; override;
    function RaiseToRat(R: TAlgosimRationalNumber): TAlgosimNumber; override;
    function RaiseTo(ANum: TAlgosimNumber): TAlgosimNumber; override;

    function GetMemorySize: UInt64; override;

  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TASC);
    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function AsMemberOfSimplestField: TAlgosimNumber; override;
    property Value: TASC read FValue write FValue;
    function UnaryMinus: TAlgosimObject; override;
    function Conjugate: TAlgosimNumber; override;
    function Argument: TAlgosimRealNumber; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function Inverse: TAlgosimNumericEntity; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;
    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;
    procedure Defuzz(const Eps: Double = 1E-8); override;
    function ComputeFunction(const ARealDomain: TSDD; ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ComputeFunction(ARealFcn: TRealFunction;
      AComplexFcn: TComplexFunction): TAlgosimNumber; override;
    function ToRealNumber: TASR; override;
    function ToComplexNumber: TASC; override;
    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;
    function ToBoolean: Boolean; override;
    function TryToASI(out ASI: Int64): Boolean; override;
    function TryToRat(out R: TRationalNumber): Boolean; override;
    function TryToInt32(out Int: Integer): Boolean; override;
    function TryToInt64(out Int: Int64): Boolean; override;
    function TryToASR(out Val: TASR): Boolean; override;
    function TryToASC(out Val: TASC): Boolean; override;
    procedure Increase(AAmount: TASI = 1); override;

    function SortClassGetHashCode: Integer; override;
    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;
  end;

  [AlgosimObject(
    'string',
    [asoValueContainer, asoOrderedContainer],
    'txt,log,ini,url,reg,inf,xml,xsd,xsl,svg,rss,atom,xul,wml,xhtml,html,htm,' +
    'asp,php,inc,css,pas,dpr,c,h,cpp,cs,java,js,vba,py,pl,bat,cmd,ps1'
  )]
  TAlgosimString = class(TAlgosimObject)
  strict private
    function NumFix(const AStr: string): string;
  protected
    FValue: string;
    FMaxLen: Integer;
    function GetValue(Index: Integer): TAlgosimObject; override;
    function GetValueCount: Integer; override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;
    function GetMaxLen: Integer; override;
    procedure SetMaxLen(AValue: Integer); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: string);
    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function GetAsMultilineText(const AOptions: TFormatOptions): string; override;
    function ToRealNumber: TASR; override;
    function ToComplexNumber: TASC; override;
    function ToNumber: TAlgosimObject; override;
    function ToCharacter: char; override;
    function IndexOfValue(AObj: TAlgosimObject): TAlgosimObject; override;
    function First(N: Integer): TAlgosimObject; overload; override;
    function Last(N: Integer): TAlgosimObject; overload; override;
    function Part(A, B: Integer): TAlgosimObject; overload; override;
    function Part(A: Integer): TAlgosimObject; overload; override;
    function Part(const ARanges: array of TRange): TAlgosimObject; overload; override;
    function Part(const AIndices: array of Integer): TAlgosimObject; overload; override;
    function TryToASC(out Val: TASC): Boolean; override;
    function TryToASR(out Val: TASR): Boolean; override;
    function TryToASI(out ASI: TASI): Boolean; override;
    function TryToRat(out R: TRationalNumber): Boolean; override;
    function TryToInt32(out Int: Integer): Boolean; override;
    function TryToInt64(out Int: Int64): Boolean; override;
    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToVector: TAlgosimVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;
    function ToTable: TASTable; override;
    property Value: string read FValue write FValue;
    procedure Append(AElement: TAlgosimObject); override;
    procedure ExtendWith(AElement: TAlgosimObject); override;
    procedure Insert(AIndex: Integer; AElement: TAlgosimObject); override;
    procedure Truncate(ANewLength: Integer); override;
    procedure Remove(const AIndices: array of Integer); override;
    procedure Swap(Index1, Index2: Integer); override;
    procedure Shuffle; override;
    procedure Reverse; override;
    function RemoveDuplicates: TAlgosimObject; override;
    function RemoveAdjacentDuplicates: TAlgosimObject; override;
    function Count(APredicate: TASOPredicate): Integer; override;
    function ForAll(APredicate: TASOPredicate): Boolean; override;
    function Exists(APredicate: TASOPredicate): Boolean; override;
    function Filter(APredicate: TASOPredicate): TAlgosimObject; override;
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); override;
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); override;
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; override;
    procedure RemoveFirst(N: Integer = 1); override;
    function RotLeft(N: Integer): TAlgosimObject; override;
    function RotRight(N: Integer): TAlgosimObject; override;
    function ToBoolean: Boolean; override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
    class function LoadFromFile(const AFileName: string;
      AEncoding: TEncoding = nil; const AParams: string = ''): TAlgosimObject; override;
    class function Concat(const Args: array of TAlgosimString): TAlgosimString;
    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;
    function ToColor: TRGB; override;
  end;

  [AlgosimObject('boolean')]
  TAlgosimBoolean = class(TAlgosimObject)
  public const
    BoolStrs: array[Boolean] of string = ('false', 'true');
  protected var
    FValue: Boolean;
    FTrueSymbol,
    FFalseSymbol: string;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create; override;
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: Boolean);
    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function TryToASI(out ASI: Int64): Boolean; override;
    function ToRealNumber: TASR; override;
    function ToComplexNumber: TASC; override;
    function ToNumber: TAlgosimObject; override;
    function ToBoolean: Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;
    property Value: Boolean read FValue write FValue;
    property TrueSymbol: string read FTrueSymbol write FTrueSymbol;
    property FalseSymbol: string read FFalseSymbol write FFalseSymbol;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
  end;

  [AlgosimObject('success indication')]
  TAlgosimSuccessIndication = class(TAlgosimObject)
  public
  const
    SuccessStr = 'success';
    constructor Create(AObject: TAlgosimObject); override;
    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string;
      override;
    function ToBoolean: Boolean; override;
    class function CreateWithValue(ASuccess: Boolean): TAlgosimObject;
    class function SortClass: TSortClass; override;
    class function SortClassSameObject(const Left: TAlgosimObject;
      const Right: TAlgosimObject; const AEpsilon: Extended = 0): Boolean;
      override;
    function Equals(Obj: TObject): Boolean; override;
    function ToInputString: string; override;
  end;

  [AlgosimObject('control flow object')]
  TAlgosimControlFlowObject = class(TAlgosimObject)
  public
    constructor Create(AObject: TAlgosimObject); override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string;
      override;
    function ToString: string; override;
    class function SortClass: TSortClass; override;
    class function SortClassSameObject(const Left: TAlgosimObject;
      const Right: TAlgosimObject; const AEpsilon: Extended = 0): Boolean;
      override;
    function Equals(Obj: TObject): Boolean; override;
  end;

  [AlgosimObject('failure object')]
  TAlgosimFailure = class(TAlgosimControlFlowObject)
  strict protected var
    FFailureReason: string;
    FFailureSource: TList<TClass>;
  public
    function ToString: string; override;
    constructor Create; override;
    constructor Create(AObject: TAlgosimObject); override;
    destructor Destroy; override;
    property FailureReason: string read FFailureReason write FFailureReason;
    property Source: TList<TClass> read FFailureSource;
    function ToInputString: string; override;
  end;

  TAlgosimSyntaxError = class(TAlgosimFailure)
  public
    function ToString: string; override;
  end;

  TAlgosimParserError = class(TAlgosimFailure)
    function ToString: string; override;
  end;

  [AlgosimObject('break object')]
  TAlgosimBreak = class(TAlgosimControlFlowObject)
  strict protected var
    FDepth: Integer;
  public
    constructor Create; override;
    constructor CreateWithValue(ADepth: Integer);
    function ToString: string; override;
    property Depth: Integer read FDepth;
    function Consume: Boolean;
  end;

  [AlgosimObject('continue object')]
  TAlgosimContinue = class(TAlgosimControlFlowObject)
  public
    function ToString: string; override;
  end;

  PAlgosimReference = ^TAlgosimReference;

  [AlgosimObject('reference')]
  TAlgosimReference = class(TAlgosimObject)
  strict private
    FGUID: TGUID;
    FSubrefs: TObjectDictionary<string, TAlgosimReference>;
  public
    constructor Create; override;
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AGUID: TGUID);
    destructor Destroy; override;
    function Equals(Obj: TObject): Boolean; override;
    function ToString: string; override;
    property GUID: TGUID read FGUID;
    procedure AddSubref(const AName: string; ARef: TAlgosimReference); overload;
    procedure AddSubref(const AName: string; const ARef: TGUID); overload;
    function TryGetSubscriptedRef(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; override;
    function TryGetSubscriptedValue(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; override;
    procedure SaveToFile(const AFileName: string; AOptions: TAlgosimStructure;
      AContext: TObject); overload; override;
  end;

  [AlgosimObject('numeric array')]
  TAlgosimNumericArray = class abstract(TAlgosimNumericEntity)
  public const
    ParenLeftUpper = #$239B;
    ParenLeftExtension = #$239C;
    ParenLeftLower = #$239D;
    ParenRightUpper = #$239E;
    ParenRightExtension = #$239F;
    ParenRightLower = #$23A0;
  end;

  [AlgosimObject('vector')]
  TAlgosimVector = class abstract(TAlgosimNumericArray)
  protected
    FMaxLen: Integer;
    function GetDimension: Integer; virtual; abstract;
    procedure SetDimension(const Value: Integer); virtual; abstract;
    function GetElementAsStringFmt(Index: Integer; const AOptions: TFormatOptions): string; virtual; abstract;
    function GetElementAsString(Index: Integer): string; virtual; abstract;
    function GetValueCount: Integer; override;
    function GetPlanarExtent: TSize; override;
    procedure SetPlanarExtent(const Value: TSize); override;
    function GetMaxLen: Integer; override;
    procedure SetMaxLen(AValue: Integer); override;
  public
    constructor Create; override;
    function ToString: string; override;
    function ToSpeech: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function GetAsMultilineText(const AOptions: TFormatOptions): string; override;
    property Dimension: Integer read GetDimension write SetDimension;

    function Normalized: TAlgosimVector; virtual; abstract;
    function NormalizedIfNonzero: TAlgosimVector; virtual; abstract;

    function WithSpecificValues(AValues: TAlgosimArray): TAlgosimObject; override;

    class function Add(Left, Right: TAlgosimVector): TAlgosimVector; overload;
    class function Subtract(Left, Right: TAlgosimVector): TAlgosimVector; overload;
    class function Add(Left: TAlgosimVector; Right: TAlgosimNumber): TAlgosimVector; overload;
    class function Subtract(Left: TAlgosimVector; Right: TAlgosimNumber): TAlgosimVector; overload;
    class function InnerProduct(Left, Right: TAlgosimVector): TAlgosimNumber;
    class function Multiply(Left: TAlgosimVector; Right: TAlgosimNumber): TAlgosimVector;
    class function Divide(Left: TAlgosimVector; Right: TAlgosimNumber): TAlgosimVector;
    class function CrossProduct(Left, Right: TAlgosimVector): TAlgosimVector;
    class function Angle(Left, Right: TAlgosimVector): TAlgosimNumber;
    class function Concat(const Args: array of TAlgosimVector): TAlgosimVector;

    function Equals(Obj: TObject): Boolean; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  [AlgosimObject('real vector', [asoValueContainer, asoOrderedContainer])]
  TAlgosimRealVector = class(TAlgosimVector)
  protected
    FValue: TRealVector;
    function GetElementAsString(Index: Integer): string; override;
    function GetElementAsStringFmt(Index: Integer;
      const AOptions: TFormatOptions): string; override;
    function GetDimension: Integer; override;
    procedure SetDimension(const Value: Integer); override;
    function GetValue(Index: Integer): TAlgosimObject; override;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    function GetValueFromPoint(const APoint: TPoint): TAlgosimObject; override;
    procedure SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TRealVector);

    property Value: TRealVector read FValue write FValue;

    function N_sum: TAlgosimNumericEntity; override;
    function N_product: TAlgosimNumericEntity; override;
    function N_GeometricMean: TAlgosimNumber; override;
    function N_HarmonicMean: TAlgosimNumber; override;
    function N_max: TAlgosimNumber; override;
    function N_min: TAlgosimNumber; override;

    function UnaryMinus: TAlgosimObject; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;
    function IsPositive(const Eps: Double = 0): Boolean; override;
    function IsNonNegative(const Eps: Double = 0): Boolean; override;
    function IsNegative(const Eps: Double = 0): Boolean; override;
    function IsNonPositive(const Eps: Double = 0): Boolean; override;
    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;
    function Transpose: TAlgosimMatrix; override;
    function ConjugateTranspose: TAlgosimMatrix; override;

    procedure Defuzz(const Eps: Double = 1E-8); override;

    function ToComplexNumber: TASC; override;
    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;

    function AsRealVector: TRealVector; override;

    function Normalized: TAlgosimVector; override;
    function NormalizedIfNonzero: TAlgosimVector; override;

    function First(N: Integer): TAlgosimObject; overload; override;
    function Last(N: Integer): TAlgosimObject; overload; override;
    function Part(A, B: Integer): TAlgosimObject; overload; override;
    function Part(A: Integer): TAlgosimObject; overload; override;
    function Part(const ARanges: array of TRange): TAlgosimObject; overload; override;
    function Part(const AIndices: array of Integer): TAlgosimObject; overload; override;

    procedure Append(AElement: TAlgosimObject); override;
    procedure ExtendWith(AElement: TAlgosimObject); override;
    procedure Insert(AIndex: Integer; AElement: TAlgosimObject); override;
    procedure Remove(const AIndices: array of Integer); override;
    procedure Truncate(ANewLength: Integer); override;
    procedure Swap(Index1, Index2: Integer); override;

    procedure Sort; overload; override;
    procedure Sort(AComparer: IComparer<TAlgosimObject>); overload; override;
    procedure Sort(AComparer: IComparer<TASR>); overload; override;
    procedure Sort(AComparer: IComparer<TASC>); overload; override;

    procedure Shuffle; override;
    procedure Reverse; override;

    function RemoveDuplicates: TAlgosimObject; override;
    function RemoveDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; override;
    function RemoveAdjacentDuplicates: TAlgosimObject; override;
    function RemoveAdjacentDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; override;

    function Frequencies: TAlgosimArray; override;
    function FrequenciesEps(const Epsilon: TASR = 0): TAlgosimArray; override;
    function CollapseSequences: TAlgosimArray; override;
    function CollapseSequencesEps(const Epsilon: TASR = 0): TAlgosimArray; override;

    function IndexOfValue(AObj: TAlgosimObject): TAlgosimObject; override;
    function IndexOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimObject; override;
    function IndicesOfValue(AObj: TAlgosimObject): TAlgosimArray; override;
    function IndicesOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimArray; override;
    function IndicesOf(APredicate: TASOPredicate): TAlgosimArray; override;
    function Count(APredicate: TASOPredicate): Integer; override;
    function ForAll(APredicate: TASOPredicate): Boolean; override;
    function Exists(APredicate: TASOPredicate): Boolean; override;
    function Filter(APredicate: TASOPredicate): TAlgosimObject; override;
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); override;
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); override;
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; override;
    procedure RemoveFirst(N: Integer = 1); override;

    function RotLeft(N: Integer): TAlgosimObject; override;
    function RotRight(N: Integer): TAlgosimObject; override;

    function SortClassGetHashCode: Integer; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
  end;

  [AlgosimObject('complex vector', [asoValueContainer, asoOrderedContainer, asoComplex])]
  TAlgosimComplexVector = class(TAlgosimVector)
  protected
    FValue: TComplexVector;
    function GetElementAsString(Index: Integer): string; override;
    function GetElementAsStringFmt(Index: Integer;
      const AOptions: TFormatOptions): string; override;
    function GetDimension: Integer; override;
    procedure SetDimension(const Value: Integer); override;
    function GetValue(Index: Integer): TAlgosimObject; override;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    function GetValueFromPoint(const APoint: TPoint): TAlgosimObject; override;
    procedure SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TComplexVector);

    property Value: TComplexVector read FValue write FValue;

    function N_sum: TAlgosimNumericEntity; override;
    function N_product: TAlgosimNumericEntity; override;
    function N_GeometricMean: TAlgosimNumber; override;
    function N_HarmonicMean: TAlgosimNumber; override;

    function UnaryMinus: TAlgosimObject; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;

    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;

    function Transpose: TAlgosimMatrix; override;
    function ConjugateTranspose: TAlgosimMatrix; override;

    procedure Defuzz(const Eps: Double = 1E-8); override;

    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;

    function AsComplexVector: TComplexVector; override;

    function Normalized: TAlgosimVector; override;
    function NormalizedIfNonzero: TAlgosimVector; override;

    function First(N: Integer): TAlgosimObject; overload; override;
    function Last(N: Integer): TAlgosimObject; overload; override;
    function Part(A, B: Integer): TAlgosimObject; overload; override;
    function Part(A: Integer): TAlgosimObject; overload; override;
    function Part(const ARanges: array of TRange): TAlgosimObject; overload; override;
    function Part(const AIndices: array of Integer): TAlgosimObject; overload; override;

    procedure Append(AElement: TAlgosimObject); override;
    procedure ExtendWith(AElement: TAlgosimObject); override;
    procedure Insert(AIndex: Integer; AElement: TAlgosimObject); override;
    procedure Remove(const AIndices: array of integer); override;
    procedure Truncate(ANewLength: Integer); override;
    procedure Swap(Index1, Index2: Integer); override;

    // procedure Sort; overload; override; missing because there is no
    // 'natural' way to compare complex numbers
    procedure Sort(AComparer: IComparer<TAlgosimObject>); overload; override;
    procedure Sort(AComparer: IComparer<TASR>); overload; override;
    procedure Sort(AComparer: IComparer<TASC>); overload; override;

    procedure Shuffle; override;
    procedure Reverse; override;

    function RemoveDuplicates: TAlgosimObject; override;
    function RemoveDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; override;
    function RemoveAdjacentDuplicates: TAlgosimObject; override;
    function RemoveAdjacentDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; override;

    function Frequencies: TAlgosimArray; override;
    function FrequenciesEps(const Epsilon: TASR = 0): TAlgosimArray; override;
    function CollapseSequences: TAlgosimArray; override;
    function CollapseSequencesEps(const Epsilon: TASR = 0): TAlgosimArray; override;

    function IndexOfValue(AObj: TAlgosimObject): TAlgosimObject; override;
    function IndexOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimObject; override;
    function IndicesOfValue(AObj: TAlgosimObject): TAlgosimArray; override;
    function IndicesOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimArray; override;
    function IndicesOf(APredicate: TASOPredicate): TAlgosimArray; override;
    function Count(APredicate: TASOPredicate): Integer; override;
    function ForAll(APredicate: TASOPredicate): Boolean; override;
    function Exists(APredicate: TASOPredicate): Boolean; override;
    function Filter(APredicate: TASOPredicate): TAlgosimObject; override;
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); override;
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); override;
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; override;
    procedure RemoveFirst(N: Integer = 1); override;

    function RotLeft(N: Integer): TAlgosimObject; override;
    function RotRight(N: Integer): TAlgosimObject; override;

    function SortClassGetHashCode: Integer; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
  end;

  [AlgosimObject('matrix')]
  TAlgosimMatrix = class abstract(TAlgosimNumericArray)
  protected
    FMaxLen: Integer;
    function GetDimension: TMatrixSize; virtual; abstract;
    procedure SetDimension(const Value: TMatrixSize); virtual; abstract;
    function GetElementAsStringFmt(Y, X: Integer;
      const AOptions: TFormatOptions): string; virtual; abstract;
    function GetElementAsString(Y, X: Integer): string; virtual; abstract;
    function GetValueCount: Integer; override;
    function GetPlanarExtent: TSize; override;
    procedure SetPlanarExtent(const Value: TSize); override;
    function GetMaxLen: Integer; override;
    procedure SetMaxLen(AValue: Integer); override;
  public
    function ToString: string; override;
    function ToSpeech: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function GetAsMultilineText(const AOptions: TFormatOptions): string; override;
    property Dimension: TMatrixSize read GetDimension write SetDimension;

    function HermitianSquare: TAlgosimMatrix; virtual; abstract;
    function Modulus: TAlgosimMatrix; virtual; abstract;
    function Determinant: TAlgosimNumber; virtual; abstract;
    function Trace: TAlgosimNumber; virtual; abstract;
    function Rank: Integer; virtual; abstract;
    function Nullity: Integer; virtual; abstract;
    function ConditionNumber(p: Integer = 2): TASR; virtual; abstract;
    function IsSingular: Boolean; virtual; abstract;
    function DeletedAbsoluteRowSum(Index: Integer): TASR; virtual; abstract;
    function RowEchelonForm: TAlgosimMatrix; virtual; abstract;
    function ReducedRowEchelonForm: TAlgosimMatrix; virtual; abstract;
    function NumZeroRows(const AEpsilon: TASR = 0): Integer; virtual; abstract;
    function NumTrailingZeroRows(const AEpsilon: TASR = 0): Integer; virtual; abstract;
    function GramSchmidt: TAlgosimMatrix; virtual; abstract;
    function ColumnSpaceBasis: TAlgosimMatrix; virtual; abstract;
    function SimilarHessenberg: TAlgosimMatrix; virtual; abstract;
    function Eigenvalues: TComplexVector; virtual; abstract;
    function Eigenvectors: TAlgosimArray; virtual; abstract;
    function SpectralRadius: TASR; virtual; abstract;
    function SingularValues: TRealVector; virtual; abstract;
    function Vectorization: TAlgosimVector; virtual; abstract;
    function Minor(Row, Col: Integer): TAlgosimNumber; virtual; abstract;
    function Cofactor(Row, Col: Integer): TAlgosimNumber; virtual; abstract;
    function CofactorMatrix: TAlgosimMatrix; virtual; abstract;
    function AdjugateMatrix: TAlgosimMatrix; virtual; abstract;

    function MainDiagonal: TAlgosimVector; virtual; abstract;
    function Subdiagonal: TAlgosimVector; virtual; abstract;
    function Superdiagonal: TAlgosimVector; virtual; abstract;
    function Antidiagonal: TAlgosimVector; virtual; abstract;

    function WithSpecificValues(AValues: TAlgosimArray): TAlgosimObject; override;

    class function Add(Left, Right: TAlgosimMatrix): TAlgosimMatrix; overload;
    class function Subtract(Left, Right: TAlgosimMatrix): TAlgosimMatrix; overload;
    class function Add(Left: TAlgosimMatrix; Right: TAlgosimNumber): TAlgosimMatrix; overload;
    class function Subtract(Left: TAlgosimMatrix; Right: TAlgosimNumber): TAlgosimMatrix; overload;
    class function Multiply(Left, Right: TAlgosimMatrix): TAlgosimMatrix; overload;
    class function Multiply(Left: TAlgosimMatrix; Right: TAlgosimVector): TAlgosimVector; overload;
    class function Multiply(Left: TAlgosimMatrix; Right: TAlgosimNumber): TAlgosimMatrix; overload;
    class function Divide(Left: TAlgosimMatrix; Right: TAlgosimNumber): TAlgosimMatrix;
    function Power(AExp: Integer): TAlgosimMatrix; virtual; abstract;

    function Equals(Obj: TObject): Boolean; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  [AlgosimObject('real matrix', [asoValueContainer, asoOrderedContainer, asoPlanarContainer])]
  TAlgosimRealMatrix = class(TAlgosimMatrix)
  protected
    FValue: TRealMatrix;
    function GetElementAsString(Y, X: Integer): string; override;
    function GetElementAsStringFmt(Y, X: Integer;
      const AOptions: TFormatOptions): string; override;
    function GetDimension: TMatrixSize; override;
    procedure SetDimension(const Value: TMatrixSize); override;
    function GetValue(Index: Integer): TAlgosimObject; override;
    function GetValueFromPoint(const APoint: TPoint): TAlgosimObject; override;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    procedure SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TRealMatrix);

    property Value: TRealMatrix read FValue write FValue;

    function N_sum: TAlgosimNumericEntity; override;
    function N_product: TAlgosimNumericEntity; override;
    function N_GeometricMean: TAlgosimNumber; override;
    function N_HarmonicMean: TAlgosimNumber; override;
    function N_max: TAlgosimNumber; override;
    function N_min: TAlgosimNumber; override;

    function UnaryMinus: TAlgosimObject; override;
    function Power(AExp: Integer): TAlgosimMatrix; override;
    function Transpose: TAlgosimMatrix; override;
    function ConjugateTranspose: TAlgosimMatrix; override;
    function HermitianSquare: TAlgosimMatrix; override;
    function Modulus: TAlgosimMatrix; override;
    function Determinant: TAlgosimNumber; override;
    function Trace: TAlgosimNumber; override;
    function Rank: Integer; override;
    function Nullity: Integer; override;
    function ConditionNumber(p: Integer = 2): TASR; override;
    function IsSingular: Boolean; override;
    function DeletedAbsoluteRowSum(Index: Integer): TASR; override;
    function RowEchelonForm: TAlgosimMatrix; override;
    function ReducedRowEchelonForm: TAlgosimMatrix; override;
    function NumZeroRows(const AEpsilon: TASR = 0): Integer; override;
    function NumTrailingZeroRows(const AEpsilon: TASR = 0): Integer; override;
    function GramSchmidt: TAlgosimMatrix; override;
    function ColumnSpaceBasis: TAlgosimMatrix; override;
    function SimilarHessenberg: TAlgosimMatrix; override;
    function Eigenvalues: TComplexVector; override;
    function Eigenvectors: TAlgosimArray; override;
    function SpectralRadius: TASR; override;
    function SingularValues: TRealVector; override;
    function Vectorization: TAlgosimVector; override;
    function Minor(Row, Col: Integer): TAlgosimNumber; override;
    function Cofactor(Row, Col: Integer): TAlgosimNumber; override;
    function CofactorMatrix: TAlgosimMatrix; override;
    function AdjugateMatrix: TAlgosimMatrix; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function Inverse: TAlgosimNumericEntity; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;
    function IsPositive(const Eps: Double = 0): Boolean; override;
    function IsNonNegative(const Eps: Double = 0): Boolean; override;
    function IsNegative(const Eps: Double = 0): Boolean; override;
    function IsNonPositive(const Eps: Double = 0): Boolean; override;
    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;

    procedure Defuzz(const Eps: Double = 1E-8); override;

    function TryGetSubscriptedValue(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; override;
    procedure SetSubscript(ASubscript: TSubscript;
      AValue: TAlgosimObject); override;

    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;

    function AsRealVector: TRealVector; override;
    function AsRealMatrix: TRealMatrix; override;

    function Part2d(const AIndicesX, AIndicesY: array of Integer): TAlgosimObject; overload; override;

    procedure Sort; overload; override;
    procedure Sort(AComparer: IComparer<TAlgosimObject>); overload; override;
    procedure Sort(AComparer: IComparer<TASR>); overload; override;
    procedure Sort(AComparer: IComparer<TASC>); overload; override;

    procedure Shuffle; override;
    procedure Reverse; override;

    function Frequencies: TAlgosimArray; override;
    function FrequenciesEps(const Epsilon: TASR = 0): TAlgosimArray; override;

    function IndexOfValue(AObj: TAlgosimObject): TAlgosimObject; override;
    function IndexOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimObject; override;
    function IndicesOfValue(AObj: TAlgosimObject): TAlgosimArray; override;
    function IndicesOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimArray; override;
    function IndicesOf(APredicate: TASOPredicate): TAlgosimArray; override;
    function Count(APredicate: TASOPredicate): Integer; override;
    function ForAll(APredicate: TASOPredicate): Boolean; override;
    function Exists(APredicate: TASOPredicate): Boolean; override;
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); override;
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); override;
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;

    function SortClassGetHashCode: Integer; override;

    function MainDiagonal: TAlgosimVector; override;
    function Subdiagonal: TAlgosimVector; override;
    function Superdiagonal: TAlgosimVector; override;
    function Antidiagonal: TAlgosimVector; override;
  end;

  [AlgosimObject('complex matrix', [asoValueContainer, asoOrderedContainer, asoPlanarContainer, asoComplex])]
  TAlgosimComplexMatrix = class(TAlgosimMatrix)
  protected
    FValue: TComplexMatrix;
    function GetElementAsString(Y, X: Integer): string; override;
    function GetElementAsStringFmt(Y, X: Integer;
      const AOptions: TFormatOptions): string; override;
    function GetDimension: TMatrixSize; override;
    procedure SetDimension(const Value: TMatrixSize); override;
    function GetValue(Index: Integer): TAlgosimObject; override;
    function GetValueFromPoint(const APoint: TPoint): TAlgosimObject; override;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    procedure SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TComplexMatrix);

    property Value: TComplexMatrix read FValue write FValue;

    function N_sum: TAlgosimNumericEntity; override;
    function N_product: TAlgosimNumericEntity; override;
    function N_GeometricMean: TAlgosimNumber; override;
    function N_HarmonicMean: TAlgosimNumber; override;

    function UnaryMinus: TAlgosimObject; override;
    function Power(AExp: Integer): TAlgosimMatrix; override;
    function Transpose: TAlgosimMatrix; override;
    function ConjugateTranspose: TAlgosimMatrix; override;
    function HermitianSquare: TAlgosimMatrix; override;
    function Modulus: TAlgosimMatrix; override;
    function Determinant: TAlgosimNumber; override;
    function Trace: TAlgosimNumber; override;
    function Rank: Integer; override;
    function Nullity: Integer; override;
    function ConditionNumber(p: Integer = 2): TASR; override;
    function IsSingular: Boolean; override;
    function DeletedAbsoluteRowSum(Index: Integer): TASR; override;
    function RowEchelonForm: TAlgosimMatrix; override;
    function ReducedRowEchelonForm: TAlgosimMatrix; override;
    function NumZeroRows(const AEpsilon: TASR = 0): Integer; override;
    function NumTrailingZeroRows(const AEpsilon: TASR = 0): Integer; override;
    function GramSchmidt: TAlgosimMatrix; override;
    function ColumnSpaceBasis: TAlgosimMatrix; override;
    function SimilarHessenberg: TAlgosimMatrix; override;
    function Eigenvalues: TComplexVector; override;
    function Eigenvectors: TAlgosimArray; override;
    function SpectralRadius: TASR; override;
    function SingularValues: TRealVector; override;
    function Vectorization: TAlgosimVector; override;
    function Minor(Row, Col: Integer): TAlgosimNumber; override;
    function Cofactor(Row, Col: Integer): TAlgosimNumber; override;
    function CofactorMatrix: TAlgosimMatrix; override;
    function AdjugateMatrix: TAlgosimMatrix; override;
    function RealPart: TAlgosimNumericEntity; override;
    function ImaginaryPart: TAlgosimNumericEntity; override;
    function Abs: TAlgosimNumericEntity; override;
    function Square: TAlgosimNumericEntity; override;
    function Norm(AType: TNormType = ntEuclidean; AParam: Integer = 2;
      AYieldProc: TObjProc = nil): TASR; override;
    function NormSquared: TAlgosimRealNumber; override;
    function Inverse: TAlgosimNumericEntity; override;
    function ScaledBy(const AFactor: TASR): TAlgosimNumericEntity; override;
    function IsZero(const Eps: Double = 0): Boolean; override;
    function IsNonZero(const Eps: Double = 0): Boolean; override;

    procedure Defuzz(const Eps: Double = 1E-8); override;

    function TryGetSubscriptedValue(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; override;
    procedure SetSubscript(ASubscript: TSubscript;
      AValue: TAlgosimObject); override;

    function ToRealVector: TRealVector; override;
    function ToComplexVector: TComplexVector; override;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;

    function AsComplexVector: TComplexVector; override;
    function AsComplexMatrix: TComplexMatrix; override;

    function Part2d(const AIndicesX, AIndicesY: array of integer): TAlgosimObject; overload; override;

    // procedure Sort; overload; override; missing because there is no
    // 'natural' way to compare complex numbers
    procedure Sort(AComparer: IComparer<TAlgosimObject>); overload; override;
    procedure Sort(AComparer: IComparer<TASR>); overload; override;
    procedure Sort(AComparer: IComparer<TASC>); overload; override;

    procedure Shuffle; override;
    procedure Reverse; override;

    function Frequencies: TAlgosimArray; override;
    function FrequenciesEps(const Epsilon: TASR = 0): TAlgosimArray; override;

    function IndexOfValue(AObj: TAlgosimObject): TAlgosimObject; override;
    function IndexOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimObject; override;
    function IndicesOfValue(AObj: TAlgosimObject): TAlgosimArray; override;
    function IndicesOfValueEps(AObj: TAlgosimObject;
      const AEpsilon: TASR = 0): TAlgosimArray; override;
    function IndicesOf(APredicate: TASOPredicate): TAlgosimArray; override;
    function Count(APredicate: TASOPredicate): Integer; override;
    function ForAll(APredicate: TASOPredicate): Boolean; override;
    function Exists(APredicate: TASOPredicate): Boolean; override;
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); override;
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); override;
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;

    function SortClassGetHashCode: Integer; override;

    function MainDiagonal: TAlgosimVector; override;
    function Subdiagonal: TAlgosimVector; override;
    function Superdiagonal: TAlgosimVector; override;
    function Antidiagonal: TAlgosimVector; override;
  end;

  [AlgosimObject('pixmap', [asoValueContainer, asoOrderedContainer, asoPlanarContainer],
    'bmp,png,gif,jpg')]
  TAlgosimPixmap = class(TAlgosimObject)
  protected
    FValue: TASPixmap;
    function GetValue(Index: Integer): TAlgosimObject; override;
    function GetValueCount: Integer; override;
    function GetValueFromPoint(const APoint: TPoint): TAlgosimObject; override;
    function GetPlanarExtent: TSize; override;
    procedure SetPlanarExtent(const Value: TSize); override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    procedure SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject); override;
    procedure AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer = 0); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TASPixmap);
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    procedure SaveToFile(const AFileName: string); override;
    procedure SaveToFile(ADlgOwner: TComponent;
      const ADefFileName: string = ''); override;
    class function LoadFromFile(const AFileName: string;
      AEncoding: TEncoding = nil; const AParams: string = ''): TAlgosimObject; override;
    procedure CopyToClipboard; override;
    function ToString: string; override;
    property Value: TASPixmap read FValue write FValue;

    function ToRealMatrix: TRealMatrix; override;

    function Frequencies: TAlgosimArray; override;

    function Count(APredicate: TASOPredicate): Integer; override;
    function ForAll(APredicate: TASOPredicate): Boolean; override;
    function Exists(APredicate: TASOPredicate): Boolean; override;
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); override;
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); override;
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; override;

    function WithSpecificValues(AValues: TAlgosimArray): TAlgosimObject; override;

    procedure Shuffle; override;
    procedure Reverse; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  [AlgosimObject('sound', [], 'wav')]
  TAlgosimSound = class(TAlgosimObject)
  protected
    FValue: TASSound;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TASSound);
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    procedure SaveToFile(const AFileName: string); override;
    class function LoadFromFile(const AFileName: string;
      AEncoding: TEncoding = nil; const AParams: string = ''): TAlgosimObject; override;
    procedure Invoke; override;
    function ToString: string; override;
    procedure CopyToClipboard; override;
    property Value: TASSound read FValue write FValue;
    function ToRealVector: TRealVector; override;
    procedure Reverse; override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  [AlgosimObject('array', [asoObjectContainer, asoOrderedContainer])]
  TAlgosimArray = class(TAlgosimObject)
  protected
    FElements: TArray<TAlgosimObject>;
    FActualLength: Integer;
    FOwnsObjects: Boolean; // only used when destroying
    FMaxLen: Integer;
    function GetElement(Index: Integer): TAlgosimObject; override;
    function GetElementCount: Integer; override;
    procedure SetElement(Index: Integer; Value: TAlgosimObject); override;
    procedure Grow;
    function GetCapacity: Integer; override;
    procedure SetCapacity(const Value: Integer); override;
    procedure SetElementCount(const AValue: Integer);
    function GetMaxLen: Integer; override;
    procedure SetMaxLen(AValue: Integer); override;
    function Is2D(out Size: TSize): Boolean;
    function GetMemorySize: UInt64; override;
  public
    destructor Destroy; override;
    constructor Create; override;
    constructor CreateUninitialized(Size: Integer);
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AElements: array of TAlgosimObject); overload;
    constructor CreateWithValue(const AElements: array of Integer); overload;
    constructor CreateWithValue(const AElements: array of TASI); overload;
    constructor CreateWithValue(const AElements: array of TASR); overload;
    constructor CreateWithValue(const AElements: array of TASC); overload;
    constructor CreateWithValue(const AElements: array of Boolean); overload;
    constructor CreateWithValue(const AElements: array of string); overload;
    constructor CreateWithValue(const AElements: array of Char); overload;
    function ToString: string; override;
    function ToSpeech: string; override;
    function ToStringArray: TArray<string>;
    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;
    function ToTable: TASTable; override;
    property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function GetAsMultilineText(const AOptions: TFormatOptions): string; override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    function AddElement(const AElement: TAlgosimObject): Boolean; override;
    property Elements[Index: Integer]: TAlgosimObject read GetElement
      write SetElement; default;
    property ElementCount: Integer read FActualLength write SetElementCount;
    procedure TrimExcess; override;
    procedure Append(AElement: TAlgosimObject); override;
    procedure ExtendWith(AElement: TAlgosimObject); override;
    class function Concat(const Args: array of TAlgosimArray): TAlgosimArray;
    function Add(const AElement: TAlgosimObject): Integer;
    procedure Insert(AIndex: Integer; AElement: TAlgosimObject); override;
    procedure Remove(const AIndices: array of Integer); override;
    procedure Clear;
    procedure Truncate(ANewLength: Integer); override;
    procedure Sort; overload; override;
    procedure Sort(AComparer: IComparer<TAlgosimObject>); overload; override;
    procedure Sort(AComparer: IComparer<TASR>); overload; override;
    procedure Sort(AComparer: IComparer<TASC>); overload; override;
    procedure Shuffle; override;
    procedure Reverse; override;
    function RemoveDuplicates: TAlgosimObject; override;
    function RemoveDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; override;
    function RemoveAdjacentDuplicates: TAlgosimObject; override;
    function RemoveAdjacentDuplicatesEps(const Epsilon: TASR = 0): TAlgosimObject; override;
    function Frequencies: TAlgosimArray; override;
    function FrequenciesEps(const Epsilon: TASR = 0): TAlgosimArray; override;
    function CollapseSequences: TAlgosimArray; override;
    function CollapseSequencesEps(const Epsilon: TASR = 0): TAlgosimArray; override;
    procedure Swap(Index1, Index2: Integer); override;
    procedure Group(AGroupSize: Integer);
    function Transpose: TAlgosimArray;
    function Zip(const AArrays: array of TAlgosimArray): TAlgosimArray;
    function RotLeft(N: Integer): TAlgosimObject; override;
    function RotRight(N: Integer): TAlgosimObject; override;
    function AsArray: TArray<TAlgosimObject>;
    function AccumulateSteps(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    procedure RemoveFirst(N: Integer = 1); override;
    function Release(Index: Integer): TAlgosimObject;
    function ExplainedOutput(const AOptions: TFormatOptions): string; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  [AlgosimObject('assignment list', [asoObjectContainer, asoOrderedContainer])]
  TAlgosimAssignmentList = class(TAlgosimArray)
  end;

  [AlgosimObject('structure', [asoObjectContainer, asoOrderedContainer])]
  TAlgosimStructure = class(TAlgosimObject)
  public type
    TMemberRef = record
      Name: string;
      Value: TAlgosimObject;
      constructor Create(const AName: string; AValue: TAlgosimObject);
    end;
  protected type
    TMemberObj = class
      Name: string;
      Value: TAlgosimObject;
      constructor Create(const AName: string; AValue: TAlgosimObject); overload;
      constructor Create(const AMemberRef: TMemberRef); overload;
      function Ref: TMemberRef;
      destructor Destroy; override;
    end;
  var
    FMembers: TObjectList<TMemberObj>;
    procedure RequestTypeChange; virtual;
    function GetMember(Index: Integer): TMemberRef;
    function GetMemberCount: Integer; inline;
    function GetValue(const AName: string): TAlgosimObject; reintroduce;
    function GetValueByIndex(Index: Integer): TAlgosimObject; inline;
    procedure SetMember(Index: Integer; const AMember: TMemberRef);
    procedure SetValue(const AName: string; const AValue: TAlgosimObject); reintroduce;
    procedure SetValueByIndex(AIndex: Integer; const AValue: TAlgosimObject);
    function GetPrefixedMultilineText(const APrefix: string;
      const AOptions: TFormatOptions): string; virtual;
    function GetElement(Index: Integer): TAlgosimObject; override;
    function GetElementCount: Integer; override;
    procedure SetElement(Index: Integer; AValue: TAlgosimObject); override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create; override;
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const ANames: array of string;
      const AValues: array of TAlgosimObject); overload;
    constructor CreateWithValue(const AMembers: array of TMemberRef); overload;
    destructor Destroy; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function GetAsMultilineText(const AOptions: TFormatOptions): string; override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    function AddElement(const AElement: TAlgosimObject): Boolean; override;
    function ToString: string; override;
    function ToSpeech: string; override;
    property Members[Index: Integer]: TMemberRef read GetMember write SetMember;
    property MemberCount: Integer read GetMemberCount;
    property Values[const AName: string]: TAlgosimObject read GetValue
      write SetValue; default;
    property Values[Index: Integer]: TAlgosimObject read GetValueByIndex
      write SetValueByIndex; default;
    procedure Release(Index: Integer); overload;
    procedure Release(const AName: string); overload;
    function TryGetSubscriptedRef(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; override;
    function TryGetSubscriptedValue(ASubscript: TSubscript;
      out AValue: TAlgosimObject): Boolean; override;
    procedure SetSubscript(ASubscript: TSubscript;
      AValue: TAlgosimObject); override;
    function Filter(APredicate: TASOPredicate): TAlgosimObject; override;
    procedure Clear;
    procedure Delete(AIndex: Integer); overload;
    procedure Delete(const AName: string); overload;
    function HasMember(const AName: string): Boolean; inline;
    function HasIntegerMember(const AName: string; out AValue: TASI): Boolean; overload;
    function HasIntegerMember(const AName: string; out AValue: Integer): Boolean; overload;
    function IndexOfName(const AName: string): Integer;
    function Add(const AName: string; const AValue: TAlgosimObject;
      ASkipUniquenessCheck: Boolean = False): Integer;
    procedure Insert(Index: Integer; const AName: string;
      const AValue: TAlgosimObject); reintroduce;
    procedure Truncate(ANewLength: Integer); override;
    procedure RenameMember(const AOldName, ANewName: string);
    class function IsValidMemberName(const AName: string): Boolean; static; inline;
    function ToStructType(const AName: string): TAlgosimStructureType;
    function ValidateAgainst(AStructureType: TAlgosimStructure): Boolean;
    function ToColor: TRGB; override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  TAlgosimTypedStructure = class;

  [AlgosimObject('structure type', [asoObjectContainer, asoOrderedContainer])]
  TAlgosimStructureType = class(TAlgosimStructure)
  strict private
    FName: string;
  public
    constructor Create(AObject: TAlgosimObject); override;
    property Name: string read FName write FName;
    function New(const AValues: array of TAlgosimObject): TAlgosimTypedStructure; overload;
    function New(const AMembers: array of TAlgosimStructure.TMemberRef): TAlgosimTypedStructure; overload;
    function New: TAlgosimTypedStructure; overload;
  end;

  [AlgosimObject('typed structure', [asoObjectContainer, asoOrderedContainer])]
  TAlgosimTypedStructure = class(TAlgosimStructure)
  protected
    FStructureTypeName: string;
    FConstructed: Boolean;
    function GetTypeName: string; override;
    procedure RequestTypeChange; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor Create(AStructureType: TAlgosimStructureType;
      const AValues: array of TAlgosimObject); overload;
    constructor Create(AStructureType: TAlgosimStructureType;
      const AMembers: array of TAlgosimStructure.TMemberRef); overload;
    procedure AfterConstruction; override;
    property StructureTypeName: string read FStructureTypeName
      write FStructureTypeName;
  end;

  [AlgosimObject('set', [asoObjectContainer])]
  TAlgosimSet = class(TAlgosimObject)
  strict private
    const MAX_EPS_CARD = 10000;
    procedure OnDictChanged(Sender: TObject; const Item: TAlgosimObject;
      Action: TCollectionNotification);
  protected
    FValue: TObjectDictionary<TAlgosimObject, Pointer>;
    FValueArray: TArray<TAlgosimObject>;
    function GetElementCount: Integer; override;
    function GetElement(Index: Integer): TAlgosimObject; override;
    function GetMemorySize: UInt64; override;
  public
    constructor Create; override;
    constructor Create(AObject: TAlgosimObject); override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    procedure Clear;
    destructor Destroy; override;
    function AddElement(const AElement: TAlgosimObject): Boolean; override;
    class function SortClass: TSortClass; override;
    function Equals(Obj: TObject): Boolean; override;
    class function SortClassCompare(const Left: TAlgosimObject;
      const Right: TAlgosimObject): Integer; override;
    function SortClassGetHashCode: Integer; override;
    class function SortClassSameObject(const Left: TAlgosimObject;
      const Right: TAlgosimObject; const AEpsilon: Extended = 0): Boolean;
      override;
    function ToString: string; override;
    function ToSpeech: string; override;
    property Cardinality: Integer read GetElementCount;
    function ToArray: TArray<TAlgosimObject>;
    class function Union(U, V: TAlgosimSet): TAlgosimSet; static;
    class function Intersection(U, V: TAlgosimSet): TAlgosimSet; static;
    class function Difference(U, V: TAlgosimSet): TAlgosimSet; static;
    class function SymmetricDifference(U, V: TAlgosimSet): TAlgosimSet; static;
    class function ElementOf(x: TAlgosimObject; U: TAlgosimSet): Boolean; static;
    class function Subset(U, V: TAlgosimSet): Boolean; static;
    class function ProperSubset(U, V: TAlgosimSet): Boolean; static;
    class function CartesianProduct(U, V: TAlgosimSet): TAlgosimSet; overload; static;
    class function CartesianProduct(const ASets: array of TAlgosimSet): TAlgosimSet; overload; static;
  end;

  [AlgosimObject('table', [asoValueContainer, asoOrderedContainer, asoPlanarContainer])]
  TAlgosimTable = class(TAlgosimObject)
  protected
    FValue: TASTable;
    FAlignment: TAlignment;
    FColSpacing: Integer;
    function GetValue(Index: Integer): TAlgosimObject; override;
    function GetValueCount: Integer; override;
    function GetValueFromPoint(const APoint: TPoint): TAlgosimObject; override;
    function GetPlanarExtent: TSize; override;
    procedure SetPlanarExtent(const Value: TSize); override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    procedure SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject); override;
  public
    constructor Create; override;
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const AValue: TASTable);
    procedure SaveToFile(const AFileName: string); override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    destructor Destroy; override;
    property Value: TASTable read FValue write FValue;
    property Alignment: TAlignment read FAlignment write FAlignment;
    property ColSpacing: Integer read FColSpacing write FColSpacing;

    function ToString: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function GetAsMultilineText(const AOptions: TFormatOptions): string; override;

    function Count(APredicate: TASOPredicate): Integer; override;
    function ForAll(APredicate: TASOPredicate): Boolean; override;
    function Exists(APredicate: TASOPredicate): Boolean; override;
    procedure Apply(AFunction: TASOFunction; ACondition: TASOPredicate = nil;
      ALevel: Integer = 1); override;
    procedure Replace(APredicate: TASOPredicate; ANewValue: TAlgosimObject;
      ALevel: Integer = 1); override;
    function Accumulate(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimObject; override;
    function AccumulateStepsList(AInitialValue: TAlgosimObject;
      AFunction: TASOAccumulator): TAlgosimArray; override;

    function WithSpecificValues(AValues: TAlgosimArray): TAlgosimObject; override;

    function ToRealMatrix: TRealMatrix; override;
    function ToComplexMatrix: TComplexMatrix; override;
    function ToMatrix: TAlgosimMatrix; override;
    function ToTable: TASTable; override;

    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  [AlgosimObject('color')]
  TAlgosimColor = class(TAlgosimObject)
  strict private
    function GetAsPixel: TASPixel; inline;
    procedure SetAsPixel(const APixel: TASPixel); inline;
  protected
    FData: packed record
      FValue: TRGB;
      FAlpha: Double;
    end;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); overload; override;
    constructor CreateWithValue(const AValue: TRGB; const AAlpha: Double = 1); overload;
    constructor CreateWithValue(const AValue: THSV; const AAlpha: Double = 1); overload;
    constructor CreateWithValue(const AValue: THSL; const AAlpha: Double = 1); overload;
    constructor CreateWithValue(const AValue: TColor; const AAlpha: Double = 1); overload;
    function ToString: string; override;
    function ToSpeech: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function ToInputString: string; override;
    function ExplainedOutput(const AOptions: TFormatOptions): string; override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    function TryToInt32(out Int: Integer): Boolean; override;
    function TryToASI(out ASI: TASI): Boolean; override;
    function ToColor: TRGB; override;
    function ToPixel: TASPixel; override;
    constructor Create; overload; override;
    property Value: TRGB read FData.FValue write FData.FValue;
    property Alpha: Double read FData.FAlpha write FData.FAlpha;
    property AsPixel: TASPixel read GetAsPixel write SetAsPixel;
    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;
    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

  [AlgosimObject('binary data', [asoValueContainer, asoOrderedContainer])]
  TAlgosimBinaryData = class(TAlgosimObject)
  strict private
    function GetDataLength: NativeInt;
    procedure SetDataLength(const Value: NativeInt);
    function GetDataPtr: PByte;
  protected
    FData: TArray<Byte>;
    function GetValue(Index: Integer): TAlgosimObject; override;
    function GetValueCount: Integer; override;
    procedure SetValue(Index: Integer; AValue: TAlgosimObject); override;
    function ToASO<T: TAlgosimObject>: T;
    function GetMemorySize: UInt64; override;
  public
    constructor Create(AObject: TAlgosimObject); override;
    constructor CreateWithValue(const ABytes: array of Byte); overload;
    function ToString: string; override;
    function ToSpeech: string; override;
    function GetAsSingleLineText(const AOptions: TFormatOptions): string; override;
    function GetAsMultilineText(const AOptions: TFormatOptions): string; override;
    function Equals(Obj: TObject): Boolean; override;
    function SortClassGetHashCode: Integer; override;
    procedure SaveToFile(const AFileName: string); override;
    class function LoadFromFile(const AFileName: string;
      AEncoding: TEncoding = nil; const AParams: string = ''): TAlgosimObject; override;
    function ToInteger: TASI; override;
    function ToRationalNumber: TRationalNumber; override;
    function ToRealNumber: TASR; override;
    function ToComplexNumber: TASC; override;
    function TryToASI(out ASI: Int64): Boolean; override;
    function ToBoolean: Boolean; override;
    property Data: PByte read GetDataPtr;
    property DataLength: NativeInt read GetDataLength write SetDataLength;
    procedure Truncate(ANewLength: Integer); override;

    function GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean; override;
    procedure SetBinaryData(const Buf: PByte; const Len: UInt64); override;

    class function SortClass: TSortClass; override;
    class function SortClassCompare(const Left, Right: TAlgosimObject): Integer; override;
    class function SortClassSameObject(const Left, Right: TAlgosimObject;
      const AEpsilon: TASR = 0): Boolean; override;
  end;

function CompareASO(const Left, Right: TAlgosimObject): Integer;
function SameASO(const Left, Right: TAlgosimObject;
  const AEpsilon: TASR = 0): Boolean; inline;


type
  TASOSignal = (success, failure, null, _break, _continue);

function ASO(const Value: TASR): TAlgosimRealNumber; overload; inline;
function ASO(const Value: TASR; AFormatStyle: TFormatStyle): TAlgosimRealNumber; overload; inline;
function ASO(const Value: TASC): TAlgosimComplexNumber; overload; inline;
function ASO(const Value: string): TAlgosimString; overload; inline;
function ASO(const Value: Boolean): TAlgosimBoolean; overload; inline;
function ASO(const Value: TRealVector): TAlgosimRealVector; overload; inline;
function ASO(const Value: TComplexVector): TAlgosimComplexVector; overload; inline;
function ASO(const Value: TRealMatrix): TAlgosimRealMatrix; overload; inline;
function ASO(const Value: TComplexMatrix): TAlgosimComplexMatrix; overload; inline;
function ASO(const Value: TASPixmap): TAlgosimPixmap; overload; inline;
function ASO(const Value: TASSound): TAlgosimSound; overload; inline;
function ASO(const Value: TASTable): TAlgosimTable; overload; inline;
function ASO(const Value: TRGB): TAlgosimColor; overload; inline;
function ASO(const Value: THSV): TAlgosimColor; overload; inline;
function ASO(const Value: THSL): TAlgosimColor; overload; inline;
function ASO(const Value: TASPixel): TAlgosimColor; overload; inline;
function ASO(const Value: Exception): TAlgosimFailure; overload;
function ASOColor(const Value: TColor): TAlgosimColor; inline;
function ASO(const Elements: array of TAlgosimObject): TAlgosimArray; overload;
function ASO(const Names: array of string;
  const Values: array of TAlgosimObject): TAlgosimStructure; overload;
function ASO(const Members: array of TAlgosimStructure.TMemberRef): TAlgosimStructure; overload;
function ASO(const Value: TASOSignal; const AReason: string = ''): TAlgosimObject; overload;
function ASOInt(const Value: TASI): TAlgosimInteger; overload; inline;
function ASOInt(const Value: TASI; AFormatStyle: TFormatStyle): TAlgosimInteger; overload; inline;
function ASOInt(const Value: TASI; ABase: Integer): TAlgosimInteger; overload; inline;
function ASORat(const Value: TRationalNumber): TAlgosimRationalNumber; overload; inline;
function ASORat(const Value: TRationalNumber; AFormatStyle: TFormatStyle): TAlgosimRationalNumber; overload; inline;
function ASO(const AGUID: TGUID): TAlgosimReference; overload; inline;
function ASOBreak(ADepth: Integer = 1): TAlgosimBreak;
function ASOContinue: TAlgosimContinue;

function sm(const AName: string; AValue: TAlgosimObject): TAlgosimStructure.TMemberRef; inline;

function IsNonNull(AObject: TAlgosimObject): Boolean; inline;
function IsControl(AObject: TAlgosimObject): Boolean; inline;
function IsFailure(AObject: TAlgosimObject): Boolean; inline;
function IsCharacter(AObject: TAlgosimObject): Boolean; inline;
function IsTypedStructure(AObject: TAlgosimObject;
  AType: TAlgosimStructureType): Boolean; overload; inline;

const
  NormTypes: array[TNormType] of string = ('Euclidean norm', 'Frobenius norm',
    'p-norm', 'max norm', 'sum norm', 'k-norm', 'max column sum norm',
    'max row sum norm', 'spectral norm');

  ShortNormTypes: array[TNormType] of string = ('Euclidean', 'Frobenius',
    'p', 'max', 'sum', 'k', 'max column sum', 'max row sum', 'spectral');

type
  TNormTypeHelper = record helper for TNormType
    function ToString: string;
    function ToShortString: string;
    class function FromString(const AStr: string): TNormType; static;
  end;

const
  NumArrClasses: array[{2d}Boolean, {cplx}Boolean] of TAlgosimNumericArrayClass =
    (
      (TAlgosimRealVector, TAlgosimComplexVector),
      (TAlgosimRealMatrix, TAlgosimComplexMatrix)
    );

function NumArrayClass(AMatrix, AComplex: Boolean): TAlgosimNumericArrayClass; inline;

procedure MakeComplex(var AObj: TAlgosimObject);

type
  TASOArrSpec = record
    class function TrySpec<T: TAlgosimObject>(
      const AArgs: TArray<TAlgosimObject>; out ASpec: TArray<T>): Boolean; static;
  end;

var
  Debug_DisableASOHashing: Boolean;

function LoadResObject(const AName: string): TAlgosimObject;

implementation

uses
  Windows, StrUtils, Character, Graphics, Clipbrd, ASFormatters, ASStructs,
  Rtti, IOUtils, TextEncodings, System.Hash, Dialogs, ASExecutionContext;

function CapCap(ACapacity: Integer): Integer; inline;
begin
  if ACapacity <= 1024 then
    Result := ACapacity
  else
    Result := 1024;
end;

{$IFOPT Q+}
  {$DEFINE OverflowCheckingWasEnabled}
  {$Q-}
{$ELSE}
  {$UNDEF OverflowCheckingWasEnabled}
{$ENDIF}

function CombineHashes(const Values: array of Integer): Integer;
var
  Value: Integer;
begin
  Result := 17;
  for Value in Values do
    Result := 37 * Result + Value;
end;

{$IFDEF OverflowCheckingWasEnabled}
  {$Q+}
  {$UNDEF OverflowCheckingWasEnabled}
{$ENDIF}

function CompareASO(const Left, Right: TAlgosimObject): Integer;
begin
  Result := CompareValue(Ord(Left.SortClass), Ord(Right.SortClass));
  if Result = 0 then
    Result := Left.SortClassCompare(Left, Right);
end;

function SameASO(const Left, Right: TAlgosimObject; const AEpsilon: TASR): Boolean;
begin
  Result := (Left.SortClass = Right.SortClass) and
    Left.SortClassSameObject(Left, Right, AEpsilon);
end;

function NumArrayClass(AMatrix, AComplex: Boolean): TAlgosimNumericArrayClass;
begin
  Result := NumArrClasses[AMatrix, AComplex];
end;

procedure MakeComplex(var AObj: TAlgosimObject);
var
  OldObj: TAlgosimObject;
begin

  if not (AObj is TAlgosimNumericEntity) or AObj.IsComplex then
    Exit;

  OldObj := AObj;

  if AObj is TAlgosimNumber then
  begin
    AObj := ASO(OldObj.ToASC);
    OldObj.Free;
  end

  else if AObj is TAlgosimVector then
  begin
    AObj := ASO(OldObj.AsComplexVector);
    OldObj.Free;
  end

  else if AObj is TAlgosimMatrix then
  begin
    AObj := ASO(OldObj.AsComplexMatrix);
    OldObj.Free;
  end;

end;

function PadStr(const AStr: string; const ALen: Integer;
  const AAlign: TAlignment = taCenter): string;
var
  PadLen: Integer;
begin
  Result := AStr;
  PadLen := Max(ALen - AStr.Length, 0);
  case AAlign of
    taLeftJustify:
      Result := AStr + StringOfChar(#32, PadLen);
    taRightJustify:
      Result := StringOfChar(#32, PadLen) + AStr;
    taCenter:
      Result := StringOfChar(#32, PadLen div 2) + AStr + StringOfChar(#32, PadLen - PadLen div 2);
  end;
end;

{ TAlgosimObject }

constructor TAlgosimObject.Create;
begin

end;

function TAlgosimObject.Accumulate(AInitialValue: TAlgosimObject;
  AFunction: TASOAccumulator): TAlgosimObject;
var
  i: Integer;
  NewVal: TAlgosimObject;
begin
  Result := AInitialValue.Clone;
  try
    if IsObjectContainer then
      for i := 1 to ElementCount do
        TObjReplacer<TAlgosimObject>.Replace(Result, AFunction(Result, Elements[i]))
    else if IsValueContainer then
      for i := 1 to ValueCount do
      begin
        NewVal := Values[i];
        try
          TObjReplacer<TAlgosimObject>.Replace(Result, AFunction(Result, NewVal));
        finally
          NewVal.Free;
        end;
      end
    else
      raise EAlgosimObjectException.CreateFmt(SCannotAccumulateElements,
        [ClassTypeName]);
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.AccumulateSteps(AInitialValue: TAlgosimObject;
  AFunction: TASOAccumulator): TAlgosimObject;
var
  List: TAlgosimArray;
begin
  List := AccumulateStepsList(AInitialValue, AFunction);
  try
    Result := WithSpecificValues(List);
  finally
    List.Free;
  end;
end;

function TAlgosimObject.AccumulateStepsList(AInitialValue: TAlgosimObject;
  AFunction: TASOAccumulator): TAlgosimArray;
var
  i: Integer;
  Val: TAlgosimObject;
begin
  Result := TAlgosimArray.Create;
  try
    if IsObjectContainer then
    begin
      Result.Capacity := ElementCount;
      for i := 1 to ElementCount do
      begin
        AInitialValue := AFunction(AInitialValue, Elements[i]);
        Result.Add(AInitialValue);
      end;
    end
    else if IsValueContainer then
    begin
      Result.Capacity := ValueCount;
      for i := 1 to ValueCount do
      begin
        Val := Values[i];
        try
          AInitialValue := AFunction(AInitialValue, Val);
          Result.Add(AInitialValue);
        finally
          Val.Free;
        end;
      end;
    end
    else
      raise EAlgosimObjectException.CreateFmt(SCannotAccumulateElements,
        [ClassTypeName]);
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.AddElement(const AElement: TAlgosimObject): Boolean;
begin
  AElement.Free;
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

procedure TAlgosimObject.AddMembersToArray(AArray: TAlgosimArray;
  APredicate: TASOPredicate; ALevel: Integer);
var
  i: Integer;
  obj, objref: TAlgosimObject;
begin

  if ALevel = 1 then
  begin
    if IsObjectContainer then
    begin
      for i := 1 to ElementCount do
        if not Assigned(APredicate) or APredicate(Elements[i]) then
          AArray.Add(Elements[i].Clone);
    end
    else if IsValueContainer then
    begin
      for i := 1 to ValueCount do
      begin
        obj := Values[i];
        try
          if not Assigned(APredicate) or APredicate(Obj) then
          begin
            objref := obj;
            obj := nil;
            AArray.Add(objref);
          end;
        finally
          obj.Free;
        end;
      end;
    end;
  end
  else if (ALevel > 1) and IsObjectContainer then
    for i := 1 to ElementCount do
      Elements[i].AddMembersToArray(AArray, APredicate, ALevel - 1);

end;

procedure TAlgosimObject.AddMembersToArray(AArray: TAlgosimArray;
  APredicate: TASOPredicate);
var
  i: Integer;
  obj, objref: TAlgosimObject;
begin

  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
    begin
      if not Assigned(APredicate) or APredicate(Elements[i]) then
        AArray.Add(Elements[i].Clone);
      Elements[i].AddMembersToArray(AArray, APredicate);
    end;
  end
  else if IsValueContainer and not (Self is TAlgosimString) then
  begin
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        if not Assigned(APredicate) or APredicate(Obj) then
        begin
          objref := obj;
          obj := nil;
          AArray.Add(objref);
        end;
      finally
        obj.Free;
      end;
    end;
  end;

end;

procedure TAlgosimObject.AddNumbersToArray(AArray: TAlgosimArray;
  ALevel: Integer);
var
  i: Integer;
  obj: TAlgosimObject;
begin

  if ALevel > 64 then
    raise Exception.Create('TAlgosimObject.AddNumbersToArray: Too deep recursion.');

  if IsObjectContainer then
    for i := 1 to ElementCount do
      Elements[i].AddNumbersToArray(AArray, ALevel + 1)
  else if IsValueContainer then
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        obj.AddNumbersToArray(AArray, ALevel + 1)
      finally
        obj.Free;
      end;
    end;

end;

procedure TAlgosimObject.Append(AElement: TAlgosimObject);
begin
  AElement.Free;
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

procedure TAlgosimObject.Apply(AFunction: TASOFunction;
  ACondition: TASOPredicate; ALevel: Integer);
var
  i: Integer;
begin
  if IsObjectContainer then
  begin
    if ALevel > 1 then
      for i := 1 to ElementCount do
        Elements[i].Apply(AFunction, ACondition, ALevel - 1)
    else
      for i := 1 to ElementCount do
        if not Assigned(ACondition) or ACondition(Elements[i]) then
          Elements[i] := AFunction(Elements[i]);
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotApply, [ClassTypeName]);
end;

function TAlgosimObject.AsComplexMatrix: TComplexMatrix;
begin
  Result := ToComplexMatrix;
end;

function TAlgosimObject.AsComplexVector: TComplexVector;
begin
  Result := ToComplexVector;
end;

function TAlgosimObject.AsMatrix: TAlgosimMatrix;
begin
  if IsComplex then
    Result := ASO(AsComplexMatrix)
  else
    Result := ASO(AsRealMatrix);
end;

function TAlgosimObject.ASOClassType: TAlgosimObjectClass;
begin
  Result := TAlgosimObjectClass(ClassType);
end;

function TAlgosimObject.AsRealMatrix: TRealMatrix;
begin
  Result := ToRealMatrix;
end;

function TAlgosimObject.AsRealVector: TRealVector;
begin
  Result := ToRealVector;
end;

function TAlgosimObject.AsVector: TAlgosimVector;
begin
  if IsComplex then
    Result := ASO(AsComplexVector)
  else
    Result := ASO(AsRealVector);
end;

procedure TAlgosimObject.ExtendWith(AElement: TAlgosimObject);
begin
  AElement.Free;
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

function TAlgosimObject.Clone: TAlgosimObject;
begin
  Result := TAlgosimObjectClass(ClassType).Create(Self);
end;

procedure TAlgosimObject.CopyToClipboard;
begin
  Clipboard.AsText := ToString;
end;

function TAlgosimObject.Count(APredicate: TASOPredicate): Integer;
var
  i: Integer;
  obj: TAlgosimObject;
begin
  if IsObjectContainer then
  begin
    Result := 0;
    for i := 1 to ElementCount do
      if APredicate(Elements[i]) then
        Inc(Result);
  end
  else if IsValueContainer then
  begin
    Result := 0;
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        if APredicate(obj) then
          Inc(Result);
      finally
        obj.Free;
      end;
    end;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotCountElements,
      [ClassTypeName]);
end;

function TAlgosimObject.CountValue(AObj: TAlgosimObject): Integer;
var
  i: Integer;
  obj: TAlgosimObject;
begin
  if IsObjectContainer then
  begin
    Result := 0;
    for i := 1 to ElementCount do
      if Elements[i].Equals(AObj) then
        Inc(Result);
  end
  else if IsValueContainer then
  begin
    Result := 0;
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        if obj.Equals(AObj) then
          Inc(Result);
      finally
        obj.Free;
      end;
    end;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotCountElements,
      [ClassTypeName]);
end;

function TAlgosimObject.CountValueEps(AObj: TAlgosimObject;
  const AEpsilon: TASR): Integer;
var
  i: Integer;
  obj: TAlgosimObject;
begin
  if IsObjectContainer then
  begin
    Result := 0;
    for i := 1 to ElementCount do
      if SameASO(Elements[i], AObj, AEpsilon) then
        Inc(Result);
  end
  else if IsValueContainer then
  begin
    Result := 0;
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        if SameASO(obj, AObj, AEpsilon) then
          Inc(Result);
      finally
        obj.Free;
      end;
    end;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotCountElements,
      [ClassTypeName]);
end;

function TAlgosimObject.Columns: TAlgosimArray;
var
  i: Integer;
begin
  Result := TAlgosimArray.Create;
  try
    for i := 1 to PlanarExtent.cx do
      Result.Add(Column(i));
  except
    Result.Free;
    raise;
  end;
end;

class function TAlgosimObject.Comparer: IComparer<TAlgosimObject>;
begin
  Result := TComparer<TAlgosimObject>.Construct(CompareASO);
end;

function TAlgosimObject.Contains(AObj: TAlgosimObject): Boolean;
var
  Idx: TAlgosimObject;
begin
  Idx := IndexOfValue(AObj);
  try
    Result := IsNonNull(Idx);
  finally
    Idx.Free;
  end;
end;

function TAlgosimObject.ContainsEps(AObj: TAlgosimObject;
  const AEpsilon: TASR): Boolean;
var
  Idx: TAlgosimObject;
begin
  Idx := IndexOfValueEps(AObj, AEpsilon);
  try
    Result := IsNonNull(Idx);
  finally
    Idx.Free;
  end;
end;

function TAlgosimObject.CollapseSequences: TAlgosimArray;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructFreqAdj, [ClassTypeName]);
end;

function TAlgosimObject.CollapseSequencesEps(const Epsilon: TASR): TAlgosimArray;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructFreqAdj, [ClassTypeName]);
end;

function TAlgosimObject.Column(const AIndex: Integer): TAlgosimObject;
begin
  Result := GetSubscriptedValue(TSubscript.Create(skColIndex, AIndex));
end;

constructor TAlgosimObject.Create(AObject: TAlgosimObject);
begin
  raise EAlgosimObjectException.CreateFmt(SNoCopyConstructor, [ClassTypeName]);
end;

function TAlgosimObject.ElementsAre(
  AASOMetaclass: TAlgosimObjectClass): Boolean;
var
  i: Integer;
begin
  for i := 1 to ElementCount do
    if not (Elements[i] is AASOMetaclass) then
      Exit(False);
  Result := True;
end;

class function TAlgosimObject.ValEqualityComparer: IEqualityComparer<TAlgosimObject>;
begin
  Result := TEqualityComparer<TAlgosimObject>.Construct(
    TAlgosimObject.EqualityComparison,
    TAlgosimObject.Hasher
  );
end;

class function TAlgosimObject.EqualityComparison(const Left,
  Right: TAlgosimObject): Boolean;
begin
  Result := Left.Equals(Right);
end;

function TAlgosimObject.Equals(Obj: TObject): Boolean;
begin
  Result := False;
end;

function TAlgosimObject.Exists(APredicate: TASOPredicate): Boolean;
var
  i: Integer;
  obj: TAlgosimObject;
begin
  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
      if APredicate(Elements[i]) then
        Exit(True);
    Result := False;
  end
  else if IsValueContainer then
  begin
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        if APredicate(obj) then
          Exit(True);
      finally
        obj.Free;
      end;
    end;
    Result := False;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotCountElements,
      [ClassTypeName]);
end;

function TAlgosimObject.ExistsUnique(APredicate: TASOPredicate): Boolean;
var
  i, c: Integer;
  obj: TAlgosimObject;
begin
  c := 0;
  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
      if APredicate(Elements[i]) then
      begin
        Inc(c);
        if c > 1 then
          Exit(False);
      end;
    Result := c = 1;
  end
  else if IsValueContainer then
  begin
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        if APredicate(obj) then
        begin
          Inc(c);
          if c > 1 then
            Exit(False);
        end;
      finally
        obj.Free;
      end;
    end;
    Result := c = 1;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotCountElements,
      [ClassTypeName]);
end;

function TAlgosimObject.ExplainedOutput(const AOptions: TFormatOptions): string;
begin
  Result := GetAsMultilineText(AOptions);
end;

function TAlgosimObject.Filter(APredicate: TASOPredicate): TAlgosimObject;
var
  i: Integer;
begin
  if IsObjectContainer then
  begin
    Result := TAlgosimObjectClass(ClassType).Create;
    try
      Result.Capacity := ElementCount;
      for i := 1 to ElementCount do
        if APredicate(Elements[i]) then
          Result.AddElement(Elements[i].Clone);
      Result.TrimExcess;
    except
      Result.Free;
      raise;
    end;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotFilter, [ClassTypeName]);
end;

function TAlgosimObject.First(N: Integer): TAlgosimObject;
begin
  Result := Part(1, N);
end;

function TAlgosimObject.ForAll(APredicate: TASOPredicate): Boolean;
var
  i: Integer;
  obj: TAlgosimObject;
begin
  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
      if not APredicate(Elements[i]) then
        Exit(False);
    Result := True;
  end
  else if IsValueContainer then
  begin
    for i := 1 to ValueCount do
    begin
      obj := Values[i];
      try
        if not APredicate(obj) then
          Exit(False);
      finally
        obj.Free;
      end;
    end;
    Result := True;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotCountElements,
      [ClassTypeName]);
end;

function TAlgosimObject.Frequencies: TAlgosimArray;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructFreq, [ClassTypeName]);
end;

function TAlgosimObject.FrequenciesEps(const Epsilon: TASR): TAlgosimArray;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructFreq, [ClassTypeName]);
end;

function TAlgosimObject.GetAsMultilineText(const AOptions: TFormatOptions): string;
begin
  Result := GetAsSingleLineText(AOptions);
end;

function TAlgosimObject.GetAsSingleLineText(const AOptions: TFormatOptions): string;
begin
  Result := '';
end;

function TAlgosimObject.GetBinaryData(var Buf: PByte; var Len: UInt64): Boolean;
begin
  Buf := nil;
  Len := 0;
  Result := False;
end;

function TAlgosimObject.GetElement(Index: Integer): TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

function TAlgosimObject.GetElementCount: Integer;
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

function TAlgosimObject.GetHashCode: Integer;
begin
  Result := CombineHashes([Ord(SortClass), SortClassGetHashCode]);
end;

function TAlgosimObject.SortClassGetHashCode: Integer;
begin
  Result := 0;
end;

class function TAlgosimObject.Hasher(const Value: TAlgosimObject): Integer;
begin
  Result := Value.GetHashCode;
end;

procedure TAlgosimObject.SetElement(Index: Integer; AValue: TAlgosimObject);
begin
  AValue.Free; // since we own it
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

procedure TAlgosimObject.SetMaxLen(AValue: Integer);
begin
  raise EAlgosimObjectException.CreateFmt(SNoMaxLen, [ClassTypeName]);
end;

procedure TAlgosimObject.SetPlanarExtent(const Value: TSize);
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoPlanarValueContainer, [ClassTypeName]);
end;

function TAlgosimObject.GetNumbers: TAlgosimArray;
begin
  Result := TAlgosimArray.Create;
  try
    AddNumbersToArray(Result);
  except
    Result.Free;
    raise;
  end;
end;

class function TAlgosimObject.GetPhysIndex0(AIndex, ALength: Integer): Integer;
begin

  if not InRange(Abs(AIndex), 1, ALength) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [AIndex]);

  if AIndex > 0 then
    Result := AIndex - 1
  else
    Result := ALength + AIndex;

end;

class function TAlgosimObject.GetPhysIndex1(AIndex, ALength: Integer): Integer;
begin

  if not InRange(Abs(AIndex), 1, ALength) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [AIndex]);

  if AIndex > 0 then
    Result := AIndex
  else
    Result := ALength + 1 + AIndex;

end;

class function TAlgosimObject.GetPhysIndex2D0(const AIndex: TPoint;
  const ASize: TSize): TPoint;
begin

  if not InRange(Abs(AIndex.X), 1, ASize.cx) or not InRange(Abs(AIndex.Y), 1, ASize.cy) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds2D, [AIndex.Y, AIndex.X]);

  if AIndex.X > 0 then
    Result.X := AIndex.X - 1
  else
    Result.X := ASize.cx + AIndex.X;

  if AIndex.Y > 0 then
    Result.Y := AIndex.Y - 1
  else
    Result.Y := ASize.cy + AIndex.Y;

end;

function TAlgosimObject.GetPlanarExtent: TSize;
begin
  Result.cx := 1;
  Result.cy := 1;
end;

function TAlgosimObject.TryGetSubscriptedValue(
  ASubscript: TSubscript; out AValue: TAlgosimObject): Boolean;

  function SubscriptIsIntPair(out Idx1, Idx2: Integer): Boolean;
  begin
    Result := (ASubscript.Obj is TAlgosimArray) and
      (TAlgosimArray(ASubscript.Obj).ElementCount = 2) and
      (TAlgosimArray(ASubscript.Obj).ElementsAre(TAlgosimNumber)) and
      TAlgosimArray(ASubscript.Obj).Elements[1].TryToInt32(Idx1) and
      TAlgosimArray(ASubscript.Obj).Elements[2].TryToInt32(Idx2);
  end;

var
  IntIdx, IntIdx2: Integer;

begin

  AValue := nil;

  case ASubscript.Kind of
    skIndexObject:
      if (ASubscript.Obj is TAlgosimNumber) and ASubscript.Obj.TryToInt32(IntIdx) and IsContainer then
        AValue := Values[IntIdx]
      else if SubscriptIsIntPair(IntIdx, IntIdx2) and IsPlanarValueContainer then
        AValue := ValueFromPoint[
          Point(
            IntIdx2,
            IntIdx
          )];
    skFirst:
      AValue := Values[1];
    skLast:
      AValue := Values[-1];
    skRandom:
      AValue := Values[1 + System.Random(ValueCount)];
  end;

  Result := Assigned(AValue);

end;

function TAlgosimObject.TryToASI(out ASI: TASI): Boolean;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer and (ElementCount = 1) then
    Result := Elements[1].TryToASI(ASI)

  else if IsValueContainer and (ValueCount = 1) then
  begin
    obj := Values[1];
    try
      Result := obj.TryToASI(ASI);
    finally
      obj.Free;
    end;
  end

  else
    Result := False;

end;

function TAlgosimObject.TryToRat(out R: TRationalNumber): Boolean;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer and (ElementCount = 1) then
    Result := Elements[1].TryToRat(R)

  else if IsValueContainer and (ValueCount = 1) then
  begin
    obj := Values[1];
    try
      Result := obj.TryToRat(R)
    finally
      obj.Free;
    end;
  end

  else
    Result := False;

end;

function TAlgosimObject.TryToASR(out Val: TASR): Boolean;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer and (ElementCount = 1) then
    Result := Elements[1].TryToASR(Val)

  else if IsValueContainer and (ValueCount = 1) then
  begin
    obj := Values[1];
    try
      Result := obj.TryToASR(Val);
    finally
      obj.Free;
    end;
  end

  else
    Result := False;

end;

function TAlgosimObject.TryToASC(out Val: TASC): Boolean;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer and (ElementCount = 1) then
    Result := Elements[1].TryToASC(Val)

  else if IsValueContainer and (ValueCount = 1) then
  begin
    obj := Values[1];
    try
      Result := obj.TryToASC(Val);
    finally
      obj.Free;
    end;
  end

  else
    Result := False;

end;

function TAlgosimObject.TryToInt32(out Int: Int32): Boolean;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer and (ElementCount = 1) then
    Result := Elements[1].TryToInt32(Int)

  else if IsValueContainer and (ValueCount = 1) then
  begin
    obj := Values[1];
    try
      Result := obj.TryToInt32(Int);
    finally
      obj.Free;
    end;
  end

  else
    Result := False;

end;

function TAlgosimObject.TryToInt64(out Int: Int64): Boolean;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer and (ElementCount = 1) then
    Result := Elements[1].TryToInt64(Int)

  else if IsValueContainer and (ValueCount = 1) then
  begin
    obj := Values[1];
    try
      Result := obj.TryToInt64(Int);
    finally
      obj.Free;
    end;
  end

  else
    Result := False;

end;

function TAlgosimObject.GetSubscriptedValue(
  ASubscript: TSubscript): TAlgosimObject;
begin
  if not TryGetSubscriptedValue(ASubscript, Result) then
    raise EAlgosimObjectException.Create(SUnsupportedSubscriptOp);
end;

function TAlgosimObject.TryGetSubscriptedRef(
  ASubscript: TSubscript; out AValue: TAlgosimObject): Boolean;
var
  IntIdx: Integer;
begin

  AValue := nil;

  if IsObjectContainer then
    case ASubscript.Kind of
      skIndexObject:
        if (ASubscript.Obj is TAlgosimNumber) and ASubscript.Obj.TryToInt32(IntIdx) then
          AValue := Elements[IntIdx];
      skFirst:
        AValue := Elements[1];
      skLast:
        AValue := Elements[ElementCount];
      skRandom:
        AValue := Elements[1 + System.Random(ElementCount)];
    end;

  Result := Assigned(AValue);

end;

function TAlgosimObject.GetSubscriptedRef(
  ASubscript: TSubscript): TAlgosimObject;
begin
  if not TryGetSubscriptedRef(ASubscript, Result) then
    raise EAlgosimObjectException.Create(SUnsupportedSubscriptOp);
end;

function TAlgosimObject.GetTypeName: string;
begin
  Result := ClassTypeName;
end;

function TAlgosimObject.GetCapacity: Integer;
begin
  Result := -1;
end;

class constructor TAlgosimObject.ClassCreate;
var
  Context: TRttiContext;
  &Type: TRttiType;
  HasAttribute: Boolean;
  Attribute: TCustomAttribute;
begin

  _ASOClassData := TDictionary<TAlgosimObjectClass, TAlgosimObjectClassData>.Create;

  Context := TRttiContext.Create;
  try
    for &Type in Context.GetTypes do
      if &Type.IsInstance and (TRttiInstanceType(&Type).MetaclassType.InheritsFrom(TAlgosimObject)) then
      begin
        HasAttribute := False;
        for Attribute in &Type.GetAttributes do
          if Attribute is AlgosimObjectAttribute then
          begin
            _ASOClassData.Add
              (
                TAlgosimObjectClass(TRttiInstanceType(&Type).MetaclassType),
                AlgosimObjectAttribute(Attribute).Data
              );
            HasAttribute := True;
            Break;
          end;
        if not HasAttribute then
        begin
          _ASOClassData.Add
            (
              TAlgosimObjectClass(TRttiInstanceType(&Type).MetaclassType),
              TAlgosimObjectClassData.Create(
                TRttiInstanceType(&Type).MetaclassType.ClassName,
                []
              )
            );
        end;
      end
  finally
    Context.Free;
  end;

end;

class function TAlgosimObject.ClassData: TAlgosimObjectClassData;
begin
  Result := _ASOClassData[Self];
end;

class destructor TAlgosimObject.ClassDestroy;
begin
  FreeAndNil(_ASOClassData);
end;

class function TAlgosimObject.ClassFlags: TAlgosimObjectClassFlags;
begin
  Result := ClassData.ClassFlags;
end;

class function TAlgosimObject.SortClass: TSortClass;
begin
  Result := SORTCLASS_NULL;
end;

class function TAlgosimObject.SortClassCompare(const Left,
  Right: TAlgosimObject): Integer;
begin
  Result := 0;
end;

class function TAlgosimObject.SortClassSameObject(const Left,
  Right: TAlgosimObject; const AEpsilon: TASR): Boolean;
begin
  Result := False;
end;

class function TAlgosimObject.ClassTypeName: string;
begin
  Result := ClassData.ClassTypeName;
end;

function TAlgosimObject.GetValue(Index: Integer): TAlgosimObject;
begin
  Result := Elements[Index].Clone;
end;

function TAlgosimObject.GetValueCount: Integer;
begin
  Result := ElementCount;
end;

procedure TAlgosimObject.SetValue(Index: Integer; AValue: TAlgosimObject);
begin
  Elements[Index] := AValue;
end;

function TAlgosimObject.GetValueFromPoint(const APoint: TPoint): TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoPlanarValueContainer, [ClassTypeName]);
end;

function TAlgosimObject.HasElementOfClass(
  AASOMetaclass: TAlgosimObjectClass): Boolean;
var
  i: Integer;
begin
  for i := 1 to ElementCount do
    if Elements[i] is AASOMetaclass then
      Exit(True);
  Result := False;
end;

procedure TAlgosimObject.SetValueFromPoint(const APoint: TPoint; AValue: TAlgosimObject);
begin
  AValue.Free; // since we own it
  raise EAlgosimObjectException.CreateFmt(SObjectNoPlanarValueContainer, [ClassTypeName]);
end;

procedure TAlgosimObject.Shuffle;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotShuffle, [ClassTypeName]);
end;

procedure TAlgosimObject.Sort;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotSort, [ClassTypeName]);
end;

procedure TAlgosimObject.Sort(AComparer: IComparer<TASR>);
begin
  raise EAlgosimObjectException.CreateFmt(SCannotSort, [ClassTypeName]);
end;

procedure TAlgosimObject.Sort(AComparer: IComparer<TASC>);
begin
  raise EAlgosimObjectException.CreateFmt(SCannotSort, [ClassTypeName]);
end;

procedure TAlgosimObject.Sort(AComparer: IComparer<TAlgosimObject>);
begin
  raise EAlgosimObjectException.CreateFmt(SCannotSort, [ClassTypeName]);
end;

function TAlgosimObject.IndexOfValue(AObj: TAlgosimObject): TAlgosimObject;
var
  i: Integer;
  size: TSize;
  y: Integer;
  x: Integer;
  obj: TAlgosimObject;
begin

  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
      if Elements[i].Equals(AObj) then
        Exit(ASOInt(i));
    Result := ASO(null);
  end

  else if IsValueContainer then
  begin

    if IsPlanarValueContainer then
    begin
      size := GetPlanarExtent;
      for y := 1 to size.cy do
        for x := 1 to size.cx do
        begin
          obj := GetValueFromPoint(Point(x, y));
          try
            if obj.Equals(AObj) then
              Exit(TAlgosimArray.CreateWithValue([y, x]));
          finally
            FreeAndNil(obj);
          end;
        end;
      Result := ASO(null);
    end
    else
    begin
      for i := 1 to ValueCount do
      begin
        obj := Values[i];
        try
          if obj.Equals(AObj) then
            Exit(ASOInt(i));
        finally
          FreeAndNil(obj);
        end;
      end;
      Result := ASO(null);
    end;

  end

  else
    raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);

end;

function TAlgosimObject.IndexOfValueEps(AObj: TAlgosimObject;
  const AEpsilon: TASR): TAlgosimObject;
var
  i: Integer;
  size: TSize;
  y: Integer;
  x: Integer;
  obj: TAlgosimObject;
begin

  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
      if SameASO(Elements[i], AObj, AEpsilon) then
        Exit(ASOInt(i));
    Result := ASO(null);
  end

  else if IsValueContainer then
  begin

    if IsPlanarValueContainer then
    begin
      size := GetPlanarExtent;
      for y := 1 to size.cy do
        for x := 1 to size.cx do
        begin
          obj := GetValueFromPoint(Point(x, y));
          try
            if SameASO(obj, AObj, AEpsilon) then
              Exit(TAlgosimArray.CreateWithValue([y, x]));
          finally
            FreeAndNil(obj);
          end;
        end;
      Result := ASO(null);
    end
    else
    begin
      for i := 1 to ValueCount do
      begin
        obj := Values[i];
        try
          if SameASO(obj, AObj, AEpsilon) then
            Exit(ASOInt(i));
        finally
          FreeAndNil(obj);
        end;
      end;
      Result := ASO(null);
    end;

  end

  else
    raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);

end;

function TAlgosimObject.IndicesOf(APredicate: TASOPredicate): TAlgosimArray;
var
  i: Integer;
  size: TSize;
  y: Integer;
  x: Integer;
  obj: TAlgosimObject;
begin

  Result := TAlgosimArray.Create;
  try

    if IsObjectContainer and IsOrderedContainer then
    begin
      Result.Capacity := CapCap(ElementCount);
      for i := 1 to ElementCount do
        if APredicate(Elements[i]) then
          Result.Add(ASOInt(i));
      Result.TrimExcess;
    end

    else if IsValueContainer then
    begin

      Result.Capacity := CapCap(ValueCount);

      if IsPlanarValueContainer then
      begin
        size := GetPlanarExtent;
        for y := 1 to size.cy do
          for x := 1 to size.cx do
          begin
            obj := GetValueFromPoint(Point(x, y));
            try
              if APredicate(obj) then
                Result.Add(TAlgosimArray.CreateWithValue([y, x]));
            finally
              FreeAndNil(obj);
            end;
          end;
      end
      else
      begin
        for i := 1 to ValueCount do
        begin
          obj := Values[i];
          try
            if APredicate(obj) then
              Result.Add(ASOInt(i));
          finally
            FreeAndNil(obj);
          end;
        end;
      end;

      Result.TrimExcess;

    end

    else
      raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);

  except
    Result.Free;
    raise;
  end;

end;

function TAlgosimObject.IndicesOfValue(AObj: TAlgosimObject): TAlgosimArray;
var
  i: Integer;
  size: TSize;
  y: Integer;
  x: Integer;
  obj: TAlgosimObject;
begin

  Result := TAlgosimArray.Create;
  try

    if IsObjectContainer and IsOrderedContainer then
    begin
      Result.Capacity := CapCap(ElementCount);
      for i := 1 to ElementCount do
        if Elements[i].Equals(AObj) then
          Result.Add(ASOInt(i));
      Result.TrimExcess;
    end

    else if IsValueContainer then
    begin

      Result.Capacity := CapCap(ValueCount);

      if IsPlanarValueContainer then
      begin
        size := GetPlanarExtent;
        for y := 1 to size.cy do
          for x := 1 to size.cx do
          begin
            obj := GetValueFromPoint(Point(x, y));
            try
              if obj.Equals(AObj) then
                Result.Add(TAlgosimArray.CreateWithValue([y, x]));
            finally
              FreeAndNil(obj);
            end;
          end;
      end
      else
      begin
        for i := 1 to ValueCount do
        begin
          obj := Values[i];
          try
            if obj.Equals(AObj) then
              Result.Add(ASOInt(i));
          finally
            FreeAndNil(obj);
          end;
        end;
      end;

      Result.TrimExcess;

    end

    else
      raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);

  except
    Result.Free;
    raise;
  end;

end;

function TAlgosimObject.IndicesOfValueEps(AObj: TAlgosimObject;
  const AEpsilon: TASR): TAlgosimArray;
var
  i: Integer;
  size: TSize;
  y: Integer;
  x: Integer;
  obj: TAlgosimObject;
begin

  Result := TAlgosimArray.Create;
  try

    if IsObjectContainer and IsOrderedContainer then
    begin
      Result.Capacity := CapCap(ElementCount);
      for i := 1 to ElementCount do
        if SameASO(Elements[i], AObj, AEpsilon) then
          Result.Add(ASOInt(i));
      Result.TrimExcess;
    end

    else if IsValueContainer then
    begin

      Result.Capacity := CapCap(ValueCount);

      if IsPlanarValueContainer then
      begin
        size := GetPlanarExtent;
        for y := 1 to size.cy do
          for x := 1 to size.cx do
          begin
            obj := GetValueFromPoint(Point(x, y));
            try
              if SameASO(obj, AObj, AEpsilon) then
                Result.Add(TAlgosimArray.CreateWithValue([y, x]));
            finally
              FreeAndNil(obj);
            end;
          end;
      end
      else
      begin
        for i := 1 to ValueCount do
        begin
          obj := Values[i];
          try
            if SameASO(obj, AObj, AEpsilon) then
              Result.Add(ASOInt(i));
          finally
            FreeAndNil(obj);
          end;
        end;
      end;

      Result.TrimExcess;

    end

    else
      raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);

  except
    Result.Free;
    raise;
  end;

end;

procedure TAlgosimObject.Insert(AIndex: Integer; AElement: TAlgosimObject);
begin
  AElement.Free;
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

procedure TAlgosimObject.Invoke;
begin

end;

function TAlgosimObject.IsASI: Boolean;
var
  dummy: TASI;
begin
  Result := TryToASI(dummy);
end;

function TAlgosimObject.IsRat: Boolean;
var
  dummy: TRationalNumber;
begin
  Result := TryToRat(dummy);
end;

function TAlgosimObject.IsASR: Boolean;
var
  dummy: TASR;
begin
  Result := TryToASR(dummy);
end;

class function TAlgosimObject.IsContainer: Boolean;
begin
  Result := IsObjectContainer or IsValueContainer;
end;

function TAlgosimObject.IsASC: Boolean;
var
  dummy: TASC;
begin
  Result := TryToASC(dummy);
end;

function TAlgosimObject.IsInt32: Boolean;
var
  dummy: Int32;
begin
  Result := TryToInt32(dummy);
end;

function TAlgosimObject.IsInt64: Boolean;
var
  dummy: Int64;
begin
  Result := TryToInt64(dummy);
end;

function TAlgosimObject.Last(N: Integer): TAlgosimObject;
begin
  Result := Part(ValueCount - N + 1, ValueCount);
end;

class function TAlgosimObject.LoadFromFile(const AFileName: string;
  AEncoding: TEncoding; const AParams: string): TAlgosimObject;
var
  ext: string;
  classpair: TPair<TAlgosimObjectClass, TAlgosimObjectClassData>;
  TextRep: TAlgosimString;
begin

  if Self = TAlgosimObject then
  begin
    ext := ExtractFileExt(AFileName).TrimLeft(['.']);
    for classpair in _ASOClassData do
      if IndexText(ext, classpair.Value.ExportExts) <> -1 then
        Exit(classpair.Key.LoadFromFile(AFileName, AEncoding, AParams));
    raise EAlgosimObjectException.CreateFmt(SUnknownFileExt, [ext]);
  end;

  // The following makes sense in child classes of TAlgosimObject
  // and serves as a default file loader from text-based data.

  if AEncoding = nil then
    AEncoding := TEncoding.UTF8;

  TextRep := ASO(TFile.ReadAllText(AFileName, AEncoding));
  try
    Result := Self.Create(TextRep);
  finally
    TextRep.Free;
  end;

end;

function TAlgosimObject.GetIsComplex: Boolean;
var
  i: Integer;
begin

  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
      if Elements[i].IsComplex then
        Exit(True);
    Result := False;
  end

  else
    Result := asoComplex in ClassFlags;

end;

function TAlgosimObject.GetMaxLen: Integer;
begin
  raise EAlgosimObjectException.CreateFmt(SNoMaxLen, [ClassTypeName]);
end;

function TAlgosimObject.GetMemorySize: UInt64;
begin
  Result := 0;
end;

class function TAlgosimObject.IsObjectContainer: Boolean;
begin
  Result := asoObjectContainer in ClassFlags
end;

class function TAlgosimObject.IsOrderedContainer: Boolean;
begin
  Result := asoOrderedContainer in ClassFlags;
end;

class function TAlgosimObject.IsPlanarContainer: Boolean;
begin
  Result := asoPlanarContainer in ClassFlags;
end;

class function TAlgosimObject.IsPlanarValueContainer: Boolean;
begin
  Result := IsValueContainer and IsPlanarContainer;
end;

class function TAlgosimObject.IsValueContainer: Boolean;
begin
  Result := asoValueContainer in ClassFlags;
end;

procedure TAlgosimObject.NoCopyConstr(AFrom: TAlgosimObject);
begin
  raise EAlgosimObjectException.CreateFmt(SObjectTypeHasNoCopyConstrForType,
    [Self.TypeName, AFrom.TypeName]
  );
end;

procedure TAlgosimObject.SaveToFile(const AFileName: string);
var
  Stream: TStringStream;
begin
  Stream := TStringStream.Create('', TEncoding.UTF8);
  try
    Stream.WriteString(ToString);
    Stream.SaveToFile(AFileName);
  finally
    Stream.Free;
  end;
end;

procedure TAlgosimObject.SetBinaryData(const Buf: PByte; const Len: UInt64);
begin
  raise EAlgosimObjectException.CreateFmt(SSetFromBlob, [ClassTypeName]);
end;

procedure TAlgosimObject.SaveToFile(ADlgOwner: TComponent;
  const ADefFileName: string);
var
  dlg: TFileSaveDialog;
begin

  dlg := TFileSaveDialog.Create(ADlgOwner);
  try
    if Length(ClassData.ExportExts) > 0 then
    begin
      with dlg.FileTypes.Add do
      begin
        FileMask := '*.' + ClassData.ExportExts[0];
        DisplayName := TxtSentenceCase(ClassData.ExportExts[0]) + ' files';
      end;
      dlg.DefaultExtension := ClassData.ExportExts[0];
    end
    else
      with dlg.FileTypes.Add do
      begin
        FileMask := '*.*';
        DisplayName := 'All files';
      end;
    dlg.FileName := ADefFileName;
    if dlg.Execute then
      SaveToFile(dlg.FileName);
  finally
    dlg.Free;
  end;

end;

procedure TAlgosimObject.SaveToFile(const AFileName: string;
  AOptions: TAlgosimStructure; AContext: TObject);
begin
  SaveToFile(AFileName);
end;

procedure TAlgosimObject.SetBinaryData(const AData: array of Byte);
begin
//  SetBinaryData(Pointer(AData), Length(AData));
  if Length(AData) <> 0 then
    SetBinaryData(@AData[0], Length(AData))
  else
    SetBinaryData(nil, 0)
end;

procedure TAlgosimObject.SetCapacity(const Value: Integer);
begin

end;

procedure TAlgosimObject.SetSubscript(ASubscript: TSubscript;
  AValue: TAlgosimObject);

  function SubscriptIsIntPair(out Idx1, Idx2: Integer): Boolean;
  begin
    Result := (ASubscript.Obj is TAlgosimArray) and
      (TAlgosimArray(ASubscript.Obj).ElementCount = 2) and
      (TAlgosimArray(ASubscript.Obj).ElementsAre(TAlgosimNumber)) and
      TAlgosimArray(ASubscript.Obj).Elements[1].TryToInt32(Idx1) and
      TAlgosimArray(ASubscript.Obj).Elements[2].TryToInt32(Idx2);
  end;

  procedure DoFail;
  begin
    AValue.Free;
    raise EAlgosimObjectException.Create(SUnsupportedSubscriptOp);
  end;

var
  IntIdx, IntIdx2: Integer;

begin

  case ASubscript.Kind of
    skIndexObject:
      begin
        if (ASubscript.Obj is TAlgosimNumber) and ASubscript.Obj.TryToInt32(IntIdx) then
          Values[IntIdx] := AValue
        else if SubscriptIsIntPair(IntIdx, IntIdx2) and IsPlanarValueContainer then
        begin
          ValueFromPoint[
            Point(
              IntIdx2,
              IntIdx
            )] := AValue;
        end
        else
          DoFail;
      end;
    skFirst:
      Values[1] := AValue;
    skLast:
      Values[-1] := AValue;
    skRandom:
      Values[1 + System.Random(ValueCount)] := AValue;
  else
    DoFail;
  end;

end;

function TAlgosimObject.N_sum: TAlgosimNumericEntity;
var
  e: TAlgosimObject;
begin

  if IsObjectContainer then
  begin

    if ElementCount = 0 then
      Exit(ASOInt(0));

    e := Elements[1];

    if e is TAlgosimNumber then
      Result := N_NumberSum

    else if e is TAlgosimVector then
      Result := N_VectorSum

    else if e is TAlgosimMatrix then
      Result := N_MatrixSum

    else
      raise EAlgosimObjectException.Create(SCannotComputeSumOfContainer);

  end

  else if IsValueContainer then
    Result := N_NumberSum

  else
    raise EAlgosimObjectException.Create(SCannotComputeSumOfObject);

end;

procedure TAlgosimObject.Swap(Index1, Index2: Integer);
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

function TAlgosimObject.N_ArithmeticMean: TAlgosimNumericEntity;
begin

  if IsContainer then
    if ValueCount > 0 then
      with N_sum do
        try
          Result := ScaledBy(1/Self.ValueCount) {"Self" required}
        finally
          Free;
        end
    else
      raise EAlgosimObjectException.Create(SCannotComputeAvgEmptyList)
  else
    raise EAlgosimObjectException.CreateFmt(SCannotComputeAvg, [ClassTypeName]);

end;

function TAlgosimObject.N_GeometricMean: TAlgosimNumber;
var
  val: TAlgosimObject;
  Rval: TASR;
  Cval: TASC;
  i: Integer;
  p: TASR;
begin

  Rval := 1;
  Cval := 1;

  if IsContainer then
  begin
    if ValueCount > 0 then
    begin
      p := 1 / ValueCount;
      if IsObjectContainer then
      begin
        for i := 1 to ElementCount do
          if Elements[i] is TAlgosimNumber then
            if Elements[i].IsComplex then
              Cval := Cval * ASnum.cpow(Elements[i].ToASC, p)
            else
              Rval := Rval * ASnum.pow(Elements[i].ToASR, p)
          else
            raise EAlgosimObjectException.Create(SCannotComputeAvgNonSpecific)
      end
      else
      begin
        for i := 1 to ValueCount do
        begin
          val := Values[i];
          try
            if val is TAlgosimNumber then
              if val.IsComplex then
                Cval := Cval * ASnum.cpow(val.ToASC, p)
              else
                Rval := Rval * ASnum.pow(val.ToASR, p)
            else
              raise EAlgosimObjectException.Create(SCannotComputeAvgNonSpecific)
          finally
            val.Free;
          end;
        end
      end;
    end
    else
      raise EAlgosimObjectException.Create(SCannotComputeAvgEmptyList)
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotComputeAvg, [ClassTypeName]);

  if Cval = 1 then
    Result := ASO(Rval)
  else
    Result := ASO(Rval * Cval);

end;

function TAlgosimObject.N_HarmonicMean: TAlgosimNumber;
var
  val: TAlgosimObject;
  Rval: TASR;
  Cval: TASC;
  i: Integer;
begin

  Rval := 0;
  Cval := 0;

  if IsContainer then
  begin
    if ValueCount > 0 then
    begin
      if IsObjectContainer then
      begin
        for i := 1 to ElementCount do
          if Elements[i] is TAlgosimNumber then
            if Elements[i].IsComplex then
              Cval := Cval + Elements[i].ToASC.Inverse
            else
              Rval := Rval + 1 / Elements[i].ToASR
          else
            raise EAlgosimObjectException.Create(SCannotComputeAvgNonSpecific)
      end
      else
      begin
        for i := 1 to ValueCount do
        begin
          val := Values[i];
          try
            if val is TAlgosimNumber then
              if val.IsComplex then
                Cval := Cval + val.ToASC.Inverse
              else
                Rval := Rval + 1 / val.ToASR
            else
              raise EAlgosimObjectException.Create(SCannotComputeAvgNonSpecific)
          finally
            val.Free;
          end;
        end
      end;
    end
    else
      raise EAlgosimObjectException.Create(SCannotComputeAvgEmptyList)
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotComputeAvg, [ClassTypeName]);

  if Cval = 0 then
    Result := ASO(ValueCount / Rval)
  else
    Result := ASO(ValueCount / (Rval + Cval));

end;

function TAlgosimObject.N_MatrixProduct: TAlgosimMatrix;
var
  len: Integer;
  e: TAlgosimObject;
  S: TMatrixSize;
  R: TRealMatrix;
  C: TComplexMatrix;
  i: Integer;
  OnlyReal: Boolean;
begin

  if IsObjectContainer then
  begin

    len := ElementCount;
    if len = 0 then
      raise EAlgosimObjectException.Create(SCannotComputeProductOfUnknownType);

    e := Elements[1];
    if not (e is TAlgosimMatrix) then
      raise EAlgosimObjectException.Create(SCannotComputeProductOfContainer);

    S := TAlgosimMatrix(e).Dimension;

    if not S.IsSquare then
      raise EAlgosimObjectException.Create(SCannotComputeProductOfContainer);

    R := IdentityMatrix(S.Rows);
    C := ComplexIdentityMatrix(S.Rows);

    OnlyReal := true;

    for i := 1 to len do
    begin

      e := Elements[i];

      if not (e is TAlgosimMatrix) then
        raise EAlgosimObjectException.Create(SCannotComputeProductOfContainer);

      if OnlyReal then
      begin
        if e.IsComplex then
        begin
          C := R * e.AsComplexMatrix;
          OnlyReal := false;
        end
        else
          R := R * e.AsRealMatrix
      end

      else
        C := C * e.AsComplexMatrix;

    end;

    if OnlyReal then
      Exit(ASO(R))
    else
      Exit(ASO(C));

  end
  else
    raise EAlgosimObjectException.Create(SCannotComputeProductOfObject);

end;

function TAlgosimObject.N_MatrixSum: TAlgosimMatrix;
var
  len: Integer;
  size: TMatrixSize;
  e: TAlgosimObject;
  R: TRealMatrix;
  C: TComplexMatrix;
  i: Integer;
begin

  if IsObjectContainer then
  begin

    len := ElementCount;
    if len = 0 then
      raise EAlgosimObjectException.Create(SCannotComputeSumOfUnknownType);

    e := Elements[1];
    if not (e is TAlgosimMatrix) then
      raise EAlgosimObjectException.Create(SCannotComputeSumOfContainer);

    size := TAlgosimMatrix(e).Dimension;

    R := ZeroMatrix(size);
    C := ComplexZeroMatrix(size);

    for i := 1 to len do
    begin
      e := Elements[i];
      if not (e is TAlgosimMatrix) then
        raise EAlgosimObjectException.Create(SCannotComputeSumOfContainer);
      if e.IsComplex then
        C := C + e.AsComplexMatrix
      else
        R := R + e.AsRealMatrix
    end;

    if C = ComplexZeroMatrix(size) then
      Exit(ASO(R))
    else
      Exit(ASO(R + C));

  end

  else
    raise EAlgosimObjectException.Create(SCannotComputeSumOfObject);

end;

function TAlgosimObject.N_max: TAlgosimNumber;
var
  val: TAlgosimObject;
  i: Integer;
  AllInts: Boolean;
  MaxX: TASR;
  MaxN: TASI;
begin

  MaxX := 0; // to make compiler happy
  MaxN := 0;

  if IsContainer then
  begin
    if ValueCount > 0 then
    begin
      if IsObjectContainer then
      begin
        AllInts := True;
        if Elements[1] is TAlgosimNumber then
        begin
          if Elements[1] is TAlgosimInteger then
            MaxN := Elements[1].ToASI
          else
          begin
            MaxX := Elements[1].ToASR;
            AllInts := False;
          end;
        end
        else
          raise EAlgosimObjectException.Create(SCannotFindMaxNonSpecific);
        for i := 2 to ElementCount do
        begin
          if Elements[i] is TAlgosimNumber then
          begin
            if AllInts then
            begin
              if Elements[i] is TAlgosimInteger then
                MaxN := Math.Max(MaxN, Elements[i].ToASI)
              else
              begin
                MaxX := Math.Max(MaxN, Elements[i].ToASR);
                AllInts := False;
              end;
            end
            else
              MaxX := Math.Max(MaxX, Elements[i].ToASR)
          end
          else
            raise EAlgosimObjectException.Create(SCannotFindMaxNonSpecific)
        end;
        if AllInts then
          Result := ASOInt(MaxN)
        else
          Result := ASO(MaxX);
      end
      else
      begin
        val := Values[1];
        try
          if val is TAlgosimNumber then
            MaxX := val.ToASR
          else
            raise EAlgosimObjectException.Create(SCannotFindMaxNonSpecific);
        finally
          val.Free;
        end;
        for i := 2 to ValueCount do
        begin
          val := Values[i];
          try
            if val is TAlgosimNumber then
              MaxX := Math.Max(MaxX, val.ToASR)
            else
              raise EAlgosimObjectException.Create(SCannotFindMaxNonSpecific)
          finally
            val.Free;
          end;
        end;
        Result := ASO(MaxX);
      end;
    end
    else
      raise EAlgosimObjectException.Create(SCannotFindMaximumEmpty)
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotFindMax, [ClassTypeName]);

end;

function TAlgosimObject.N_min: TAlgosimNumber;
var
  val: TAlgosimObject;
  i: Integer;
  AllInts: Boolean;
  MinX: TASR;
  MinN: TASI;
begin

  MinX := 0; // to make compiler happy
  MinN := 0;

  if IsContainer then
  begin
    if ValueCount > 0 then
    begin
      if IsObjectContainer then
      begin
        AllInts := True;
        if Elements[1] is TAlgosimNumber then
        begin
          if Elements[1] is TAlgosimInteger then
            MinN := Elements[1].ToASI
          else
          begin
            MinX := Elements[1].ToASR;
            AllInts := False;
          end;
        end
        else
          raise EAlgosimObjectException.Create(SCannotFindMinNonSpecific);
        for i := 2 to ElementCount do
        begin
          if Elements[i] is TAlgosimNumber then
          begin
            if AllInts then
            begin
              if Elements[i] is TAlgosimInteger then
                MinN := Math.Min(MinN, Elements[i].ToASI)
              else
              begin
                MinX := Math.Min(MinN, Elements[i].ToASR);
                AllInts := False;
              end;
            end
            else
              MinX := Math.Min(MinX, Elements[i].ToASR)
          end
          else
            raise EAlgosimObjectException.Create(SCannotFindMinNonSpecific)
        end;
        if AllInts then
          Result := ASOInt(MinN)
        else
          Result := ASO(MinX);
      end
      else
      begin
        val := Values[1];
        try
          if val is TAlgosimNumber then
            MinX := val.ToASR
          else
            raise EAlgosimObjectException.Create(SCannotFindMinNonSpecific);
        finally
          val.Free;
        end;
        for i := 2 to ValueCount do
        begin
          val := Values[i];
          try
            if val is TAlgosimNumber then
              MinX := Math.Min(MinX, val.ToASR)
            else
              raise EAlgosimObjectException.Create(SCannotFindMinNonSpecific)
          finally
            val.Free;
          end;
        end;
        Result := ASO(MinX);
      end;
    end
    else
      raise EAlgosimObjectException.Create(SCannotFindMinimumEmpty)
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotFindMin, [ClassTypeName]);


end;

function TAlgosimObject.N_NumberProduct: TAlgosimNumber;
var
  len: Integer;
  e: TAlgosimObject;
  N: TASI;
  R: TASR;
  C: TASC;
  i: Integer;
  AllInts: Boolean;
begin

  if IsObjectContainer then
  begin

    len := ElementCount;
    if len = 0 then
      Exit(ASOInt(1));

    AllInts := True;
    N := 1;
    R := 1;
    C := 1;

    for i := 1 to len do
    begin
      e := Elements[i];
      if not (e is TAlgosimNumber) then
        raise EAlgosimObjectException.Create(SCannotComputeProductOfContainer);
      if AllInts then
      begin
        if e is TAlgosimInteger then
          N := N * TAlgosimInteger(e).Value
        else
          AllInts := False;
      end;
      if e.IsComplex then
        C := C * e.ToASC
      else
        R := R * e.ToASR;
    end;

    if AllInts and SameValue(N, R) then
      Exit(ASOInt(N))
    else if C = 1 then
      Exit(ASO(R))
    else
      Exit(ASO(R * C));

  end

  else if IsValueContainer then
  begin

    len := ValueCount;
    if len = 0 then
      Exit(ASOInt(1));

    AllInts := True;
    N := 1;
    R := 1;
    C := 1;

    for i := 1 to len do
    begin
      e := Values[i];
      try
        if not (e is TAlgosimNumber) then
          raise EAlgosimObjectException.Create(SCannotComputeProductOfContainer);
        if AllInts then
        begin
          if e is TAlgosimInteger then
            N := N * TAlgosimInteger(e).Value
          else
            AllInts := False;
        end;
        if e.IsComplex then
          C := C * e.ToASC
        else
          R := R * e.ToASR;
      finally
        e.Free;
      end;
    end;

    if AllInts and SameValue(N, R) then
      Exit(ASOInt(N))
    else if C = 1 then
      Exit(ASO(R))
    else
      Exit(ASO(R * C));

  end

  else
    raise EAlgosimObjectException.Create(SCannotComputeProductOfObject);

end;

function TAlgosimObject.N_NumberSum: TAlgosimNumber;
var
  len: Integer;
  e: TAlgosimObject;
  N: TASI;
  R: TASR;
  C: TASC;
  i: Integer;
  AllInts: Boolean;
begin

  if IsObjectContainer then
  begin

    len := ElementCount;
    if len = 0 then
      Exit(ASOInt(0));

    AllInts := True;
    N := 0;
    R := 0;
    C := 0;

    for i := 1 to len do
    begin
      e := Elements[i];
      if not (e is TAlgosimNumber) then
        raise EAlgosimObjectException.Create(SCannotComputeSumOfContainer);
      if AllInts then
      begin
        if e is TAlgosimInteger then
          N := N + TAlgosimInteger(e).Value
        else
          AllInts := False;
      end;
      if e.IsComplex then
        C := C + e.ToASC
      else
        R := R + e.ToASR;
    end;

    if AllInts and SameValue(N, R) then
      Exit(ASOInt(N))
    else if C = 0 then
      Exit(ASO(R))
    else
      Exit(ASO(R + C));

  end

  else if IsValueContainer then
  begin

    len := ValueCount;
    if len = 0 then
      Exit(ASOInt(0));

    AllInts := True;
    N := 0;
    R := 0;
    C := 0;

    for i := 1 to len do
    begin
      e := Values[i];
      try
        if not (e is TAlgosimNumber) then
          raise EAlgosimObjectException.Create(SCannotComputeSumOfContainer);
        if AllInts then
        begin
          if e is TAlgosimInteger then
            N := N + TAlgosimInteger(e).Value
          else
            AllInts := False;
        end;
        if e.IsComplex then
          C := C + e.ToASC
        else
          R := R + e.ToASR;
      finally
        e.Free;
      end;
    end;

    if AllInts and SameValue(N, R) then
      Exit(ASOInt(N))
    else if C = 0 then
      Exit(ASO(R))
    else
      Exit(ASO(R + C));

  end

  else
    raise EAlgosimObjectException.Create(SCannotComputeSumOfObject);

end;

function TAlgosimObject.N_VectorSum: TAlgosimVector;
var
  len, dim: Integer;
  e: TAlgosimObject;
  R: TRealVector;
  C: TComplexVector;
  i: Integer;
begin

  if IsObjectContainer then
  begin

    len := ElementCount;
    if len = 0 then
      raise EAlgosimObjectException.Create(SCannotComputeSumOfUnknownType);

    e := Elements[1];
    if not (e is TAlgosimVector) then
      raise EAlgosimObjectException.Create(SCannotComputeSumOfContainer);

    dim := TAlgosimVector(e).Dimension;

    R := ZeroVector(dim);
    C := ComplexZeroVector(dim);

    for i := 1 to len do
    begin
      e := Elements[i];
      if not (e is TAlgosimVector) then
        raise EAlgosimObjectException.Create(SCannotComputeSumOfContainer);
      if e.IsComplex then
        C := C + e.AsComplexVector
      else
        R := R + e.AsRealVector
    end;

    if C = ComplexZeroVector(dim) then
      Exit(ASO(R))
    else
      Exit(ASO(R + C));

  end

  else
    raise EAlgosimObjectException.Create(SCannotComputeSumOfObject);

end;

function TAlgosimObject.Part(const AIndices: array of Integer): TAlgosimObject;
var
  i: Integer;
  HighIdx: Integer;
begin
  Result := TAlgosimArray.Create;
  try
    HighIdx := ValueCount;
    Result.Capacity := Length(AIndices);
    for i := Low(AIndices) to High(AIndices) do
      if InRange(AIndices[i], 1, HighIdx) then
        Result.AddElement(Values[AIndices[i]])
      else
        raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [AIndices[i]]);
    Result.TrimExcess;
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.Part2d(const AIndicesX,
  AIndicesY: array of Integer): TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotExtractPart2d, [ClassTypeName]);
end;

function TAlgosimObject.Pick(APredicate: TASOPredicate; ALevel: Integer): TAlgosimArray;
begin
  Result := TAlgosimArray.Create;
  try
    AddMembersToArray(Result, APredicate, ALevel);
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.PickRecursive(APredicate: TASOPredicate): TAlgosimArray;
begin
  Result := TAlgosimArray.Create;
  try
    AddMembersToArray(Result, APredicate);
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.Part2d(const ARangesX,
  ARangesY: array of TRange): TAlgosimObject;
begin
  Result := Part2d(
    ParseRangeSeq(ARangesX, PlanarExtent.cx),
    ParseRangeSeq(ARangesY, PlanarExtent.cy));
end;

function TAlgosimObject.Part(const ARanges: array of TRange): TAlgosimObject;
begin
  Result := Part(ParseRangeSeq(ARanges, Self.ValueCount));
end;

function TAlgosimObject.N_product: TAlgosimNumericEntity;
var
  e: TAlgosimObject;
begin

  if IsObjectContainer then
  begin

    if ElementCount = 0 then
      Exit(ASOInt(1));

    e := Elements[1];

    if e is TAlgosimNumber then
      Result := N_NumberProduct

    else if (e is TAlgosimMatrix) and IsOrderedContainer then
      Result := N_MatrixProduct

    else
      raise EAlgosimObjectException.Create(SCannotComputeProductOfContainer);

  end

  else if IsValueContainer then
    Result := N_NumberProduct

  else
    raise EAlgosimObjectException.Create(SCannotComputeProductOfObject);

end;

procedure TAlgosimObject.Replace(APredicate: TASOPredicate;
  ANewValue: TAlgosimObject; ALevel: Integer);
var
  i: Integer;
begin
  if IsObjectContainer then
  begin
    for i := 1 to ElementCount do
      if ALevel > 1 then
        Elements[i].Replace(APredicate, ANewValue, ALevel - 1)
      else
        if not Assigned(APredicate) or APredicate(Elements[i]) then
          Elements[i] := ANewValue.Clone;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotReplace, [ClassTypeName]);
end;

procedure TAlgosimObject.Replace(AOldValue, ANewValue: TAlgosimObject;
  ALevel: Integer);
begin
  Replace(
    function(AObject: TAlgosimObject): Boolean
    begin
      Result := AObject.Equals(AOldValue)
    end,
    ANewValue,
    ALevel);
end;

procedure TAlgosimObject.Replace(ANewValue: TAlgosimObject; ALevel: Integer);
begin
  Replace(TASOPredicate(nil), ANewValue, ALevel);
end;

function TAlgosimObject.Part(A, B: Integer): TAlgosimObject;
var
  i: Integer;
begin

  Result := TAlgosimArray.Create;
  try
    if (A > B) or (A > ValueCount) or (B < 1) then Exit;
    A := Max(A, 1);
    B := Min(B, ValueCount);
    Result.Capacity := B - A + 1;
    for i := A to B do
      Result.AddElement(Values[i]);
  except
    Result.Free;
    raise;
  end;

end;

function TAlgosimObject.Part(A: Integer): TAlgosimObject;
begin
  Result := Part(A, ValueCount);
end;

procedure TAlgosimObject.Reverse;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotReverse, [ClassTypeName]);
end;

function TAlgosimObject.RotLeft(N: Integer): TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotRotate, [ClassTypeName]);
end;

function TAlgosimObject.RotRight(N: Integer): TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotRotate, [ClassTypeName]);
end;

function TAlgosimObject.Row(const AIndex: Integer): TAlgosimObject;
begin
  Result := GetSubscriptedValue(TSubscript.Create(skRowIndex, AIndex));
end;

function TAlgosimObject.Rows: TAlgosimArray;
var
  i: Integer;
begin
  Result := TAlgosimArray.Create;
  try
    for i := 1 to PlanarExtent.cy do
      Result.Add(Row(i));
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.ToASI: TASI;
begin
  if not TryToASI(Result) then
    raise EAlgosimObjectException.CreateFmt(SObjNoDBitInt, [8*Result.Size]);
end;

function TAlgosimObject.ToRat: TRationalNumber;
begin
  if not TryToRat(Result) then
    raise EAlgosimObjectException.Create(SObjNoRat);
end;

function TAlgosimObject.ToRationalNumber: TRationalNumber;
begin
  Result := ToRat;
end;

function TAlgosimObject.ToASR: TASR;
begin
  if not TryToASR(Result) then
    raise EAlgosimObjectException.Create(SObjNoFloat);
end;

function TAlgosimObject.ToASC: TASC;
begin
  if not TryToASC(Result) then
    raise EAlgosimObjectException.Create(SObjNoComplex);
end;

function TAlgosimObject.ToBoolean: Boolean;
begin
  if IsContainer then
    Result := ValueCount > 0
  else
    Result := True;
end;

function TAlgosimObject.ToCharacter: Char;
begin
  raise EAlgosimObjectException.CreateFmt(SConvChar, [ClassTypeName]);
end;

function TAlgosimObject.ToColor: TRGB;
begin
  raise EAlgosimObjectException.CreateFmt(SConvColor, [ClassTypeName]);
end;

function TAlgosimObject.ToComplexMatrix: TComplexMatrix;
begin
  raise EAlgosimObjectException.CreateFmt(SConvComplexMat, [ClassTypeName]);
end;

function TAlgosimObject.ToComplexNumber: TASC;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer then
  begin
    case ElementCount of
      0:
        raise EAlgosimObjectException.Create(SConvEmptyContNumber);
      1:
        Exit(Elements[1].ToComplexNumber)
    else
      raise EAlgosimObjectException.Create(SConvContNumber);
    end;
  end

  else if IsValueContainer then
  begin

    case ValueCount of
      0:
        raise EAlgosimObjectException.Create(SConvEmptyContNumber);
      1:
        begin
          obj := Values[1];
          try
            Exit(obj.ToComplexNumber);
          finally
            obj.Free;
          end;
        end
    else
      raise EAlgosimObjectException.Create(SConvContNumber);
    end;

  end

  else
    raise EAlgosimObjectException.CreateFmt(SConvObjComplexNum, [ClassTypeName]);

end;

function TAlgosimObject.ToComplexVector: TComplexVector;
var
  i, j, count: Integer;
begin

  if IsObjectContainer then
  begin
    count := 0;
    for i := 1 to ElementCount do
      if Elements[i] is TAlgosimNumber then
        Inc(count);
    Result.Dimension := count;
    j := 0;
    for i := 1 to ElementCount do
      if Elements[i] is TAlgosimNumber then
      begin
        Result[j] := Elements[i].ToComplexNumber;
        Inc(j);
      end;
  end

  else
    raise EAlgosimObjectException.CreateFmt(SConvComplexVect, [ClassTypeName]);

end;

function TAlgosimObject.ToInputString: string;
begin
  Result := GetAsSingleLineText(InputFormOptions);
end;

function TAlgosimObject.ToInt32: Int32;
begin
  if not TryToInt32(Result) then
    raise EAlgosimObjectException.CreateFmt(SObjNoDBitInt, [8*Result.Size]);
end;

function TAlgosimObject.ToInt64: Int64;
begin
  if not TryToInt64(Result) then
    raise EAlgosimObjectException.CreateFmt(SObjNoDBitInt, [8*Result.Size]);
end;

function TAlgosimObject.ToInteger: TASI;
begin
  Result := ToASI;
end;

function TAlgosimObject.ToList: TAlgosimArray;
var
  i: Integer;
begin
  Result := TAlgosimArray.Create;
  try
    if IsContainer then
      for i := 1 to ValueCount do
        Result.Add(Values[i])
    else
      Result.Add(Clone);
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.ToTable: TASTable;
var
  y, x: Integer;
  obj: TAlgosimObject;
begin

  Result := TASTable.Create;
  try

    if IsPlanarValueContainer then
    begin
      with PlanarExtent do
        Result.SetSize(cx, cy);
      for y := 1 to Result.Height do
        for x := 1 to Result.Width do
        begin
          obj := ValueFromPoint[Point(x, y)];
          try
            Result.Strings[Point(x - 1, y - 1)] := obj.ToString;
          finally
            obj.Free;
          end;
        end;
    end
    else if IsObjectContainer then
    begin
      Result.SetSize(1, ElementCount);
      for y := 1 to ElementCount do
        Result.Strings[Point(0, y - 1)] := Elements[y].ToString;
    end
    else if IsValueContainer then
    begin
      Result.SetSize(1, ValueCount);
      for y := 1 to ValueCount do
      begin
        obj := Values[y];
        try
          Result.Strings[Point(0, y - 1)] := obj.ToString;
        finally
          obj.Free;
        end;
      end;
    end
    else
    begin
      Result.SetSize(1, 1);
      Result.Strings[Point(0, 0)] := ToString;
    end;

  except
    Result.Free;
    raise;
  end;

end;

function TAlgosimObject.ToMatrix: TAlgosimMatrix;
begin
  if IsComplex then
    Result := ASO(ToComplexMatrix)
  else
    Result := ASO(ToRealMatrix);
end;

function TAlgosimObject.ToNumber: TAlgosimObject;
begin
  if Self is TAlgosimNumber then
    Result := Clone
  else if IsObjectContainer and (ElementCount = 1) then
    Result := Elements[1].ToNumber
  else if IsComplex then
    Result := ASO(ToComplexNumber)
  else
    Result := ASO(ToRealNumber);
end;

function TAlgosimObject.ToPixel: TASPixel;
begin
  Result := ToColor;
end;

function TAlgosimObject.ToPreviewString: string;
begin
  Result := GetAsSingleLineText(DefaultFormatOptions);
  if Result.Length > 1024 then
    SetLength(Result, 1024);
end;

function TAlgosimObject.ToRealMatrix: TRealMatrix;
begin
  raise EAlgosimObjectException.CreateFmt(SConvRealMat, [ClassTypeName]);
end;

function TAlgosimObject.ToRealNumber: TASR;
var
  obj: TAlgosimObject;
begin

  if IsObjectContainer then
  begin

    case ElementCount of
      0:
        raise EAlgosimObjectException.Create(SConvEmptyContNumber);
      1:
        Exit(Elements[1].ToRealNumber)
    else
      raise EAlgosimObjectException.Create(SConvContNumber);
    end;

  end

  else if IsValueContainer then
  begin

    case ValueCount of
      0:
        raise EAlgosimObjectException.Create(SConvEmptyContNumber);
      1:
        begin
          obj := Values[1];
          try
            Exit(obj.ToRealNumber);
          finally
            obj.Free;
          end;
        end
    else
      raise EAlgosimObjectException.Create(SConvContNumber);
    end;

  end

  else
    raise EAlgosimObjectException.CreateFmt(SConvObjRealNum, [ClassTypeName]);

end;

function TAlgosimObject.ToRealVector: TRealVector;
var
  i, j, count: Integer;
begin

  if IsObjectContainer then
  begin
    count := 0;
    for i := 1 to ElementCount do
      if Elements[i] is TAlgosimNumber then
        Inc(count);
    Result.Dimension := count;
    j := 0;
    for i := 1 to ElementCount do
      if Elements[i] is TAlgosimNumber then
      begin
        Result[j] := Elements[i].ToRealNumber;
        Inc(j);
      end;
  end

  else
    raise EAlgosimObjectException.CreateFmt(SConvRealVect, [ClassTypeName]);

end;

function TAlgosimObject.ToSet: TAlgosimSet;
var
  i: Integer;
begin
  Result := TAlgosimSet.Create;
  try
    if IsObjectContainer then
      for i := 1 to ElementCount do
        Result.AddElement(Elements[i].Clone)
    else if IsValueContainer then
      for i := 1 to ValueCount do
        Result.AddElement(Values[i])
    else
      Result.AddElement(Clone);
  except
    Result.Free;
    raise;
  end;
end;

function TAlgosimObject.ToSpeech: string;
begin
  Result := ToString;
end;

function TAlgosimObject.ToBinaryObject: TAlgosimBinaryData;
var
  buf: PByte;
  len: UInt64;
begin

  if not GetBinaryData(buf, len) then
    raise EAlgosimObjectException.CreateFmt(SConvBlob, [ClassTypeName]);

  Result := TAlgosimBinaryData.Create;
  try
    Result.DataLength := len;
    if len > 0 then
      CopyMemory(Result.Data, buf, len);
  except
    Result.Free;
    raise;
  end;

end;

function TAlgosimObject.ToString: string;
begin
  Result := GetTypeName;
end;

function TAlgosimObject.ToVector: TAlgosimVector;
begin
  if IsComplex then
    Result := ASO(ToComplexVector)
  else
    Result := ASO(ToRealVector);
end;

procedure TAlgosimObject.TrimExcess;
begin

end;

procedure TAlgosimObject.Truncate(ANewLength: Integer);
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

function TAlgosimObject.UnaryMinus: TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotComputeUnaryMinus,
    [ClassTypeName]);
end;

function TAlgosimObject.WithSpecificValues(
  AValues: TAlgosimArray): TAlgosimObject;
var
  i: Integer;
begin
  if IsContainer then
  begin
    Result := ASOClassType.Create;
    try
      for i := 1 to AValues.ElementCount do
        Result.Append(AValues.Elements[i].Clone);
    except
      Result.Free;
      raise;
    end;
  end
  else
    raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

function TAlgosimObject.Random: TAlgosimObject;
begin
  Result := Values[1 + System.Random(ValueCount)];
end;

class function TAlgosimObject.RefEqualityComparer: IEqualityComparer<TAlgosimObject>;
begin
  Result := TEqualityComparer<TAlgosimObject>.Construct(
    function(const Left, Right: TAlgosimObject): Boolean
    begin
      Result := Left = Right;
    end,
    function(const Value: TAlgosimObject): Integer
    begin
    {$IFDEF CPUX64}
      Result := Integer(IntPtr(Value)) xor Integer(IntPtr(Value) shr 32);
    {$ELSE !CPUX64}
      Result := Integer(IntPtr(Value));
    {$ENDIF !CPUX64}
    end
  );
end;

procedure TAlgosimObject.Remove(const ARanges: array of TRange);
begin
  Remove(ParseRangeSeq(ARanges, ValueCount));
end;

procedure TAlgosimObject.Remove(const AIndices: array of Integer);
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

function TAlgosimObject.RemoveAdjacentDuplicates: TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructUniqueFromSorted, [ClassTypeName]);
end;

function TAlgosimObject.RemoveAdjacentDuplicatesEps(
  const Epsilon: TASR): TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructUniqueFromSorted, [ClassTypeName]);
end;

procedure TAlgosimObject.RemoveAll(AOldValue: TAlgosimObject; ALevel: Integer);
begin
  RemoveIf(
    function(AObject: TAlgosimObject): Boolean
    begin
      Result := AObject.Equals(AOldValue)
    end,
    ALevel);
end;

function TAlgosimObject.RemoveDuplicates: TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructUnique, [ClassTypeName]);
end;

function TAlgosimObject.RemoveDuplicatesEps(
  const Epsilon: TASR): TAlgosimObject;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConstructUnique, [ClassTypeName]);
end;

procedure TAlgosimObject.RemoveFirst(N: Integer);
begin
  raise EAlgosimObjectException.CreateFmt(SObjectNoContainer, [ClassTypeName]);
end;

procedure TAlgosimObject.RemoveIf(APredicate: TASOPredicate; ALevel: Integer);
var
  i: Integer;
  IndicesToRemove: TArray<Integer>;
  c: Integer;
  Val: TAlgosimObject;
begin
  if IsObjectContainer then
  begin
    if ALevel > 1 then
      for i := 1 to ElementCount do
        Elements[i].RemoveIf(APredicate, ALevel - 1)
    else
    begin
      SetLength(IndicesToRemove, ElementCount);
      c := 0;
      for i := 1 to ElementCount do
        if not Assigned(APredicate) or APredicate(Elements[i]) then
        begin
          IndicesToRemove[c] := i;
          Inc(c);
        end;
      SetLength(IndicesToRemove, c);
      Remove(IndicesToRemove);
    end;
  end
  else if IsValueContainer and (ALevel = 1) then
  begin
    SetLength(IndicesToRemove, ValueCount);
    c := 0;
    for i := 1 to ValueCount do
    begin
      Val := Values[i];
      try
        if not Assigned(APredicate) or APredicate(Val) then
        begin
          IndicesToRemove[c] := i;
          Inc(c);
        end;
      finally
        Val.Free;
      end;
    end;
    SetLength(IndicesToRemove, c);
    Remove(IndicesToRemove);
  end
  else
    raise EAlgosimObjectException.CreateFmt(SCannotRemove, [ClassTypeName]);
end;

{ TAlgosimNullObject }

constructor TAlgosimNullObject.Create(AObject: TAlgosimObject);
begin
  Create;
end;

function TAlgosimNullObject.Equals(Obj: TObject): Boolean;
begin
  Result := Obj is TAlgosimNullObject;
end;

function TAlgosimNullObject.GetAsSingleLineText(const AOptions: TFormatOptions): string;
begin
  Result := '';
end;

class function TAlgosimNullObject.SortClassSameObject(const Left,
  Right: TAlgosimObject; const AEpsilon: TASR): Boolean;
begin
  Result := True;
end;

function TAlgosimNullObject.ToBoolean: Boolean;
begin
  Result := False;
end;

function TAlgosimNullObject.ToInputString: string;
begin
  Result := '0;';
end;

function TAlgosimNullObject.ToString: string;
begin
  Result := '';
end;

{ TAlgosimNumericEntity }

function TAlgosimNumericEntity.Abs: TAlgosimNumericEntity;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotComputeAbs, [ClassTypeName]);
end;

function TAlgosimNumericEntity.ApplyOptions(
  const AOptions: TFormatOptions): TFormatOptions;
begin
  Result := AOptions;
  if NumDigitsOverride then
    Result.Numbers.NumDigits := NumDigits;
  if NumberBase > 0 then
    Result.Numbers.Base := NumberBase;
  if DigitGroupingOverride then
  begin
    Result.Numbers.IntGrouping := DigitGrouping;
    Result.Numbers.FracGrouping := DigitGrouping;
  end;
  if NumberFormatOverride then
    Result.Numbers.NumberFormat := NumberFormat;
  if PrettyExpOverride then
    Result.Numbers.PrettyExp := PrettyExp;
  Result.Numbers.MinLength := Max(Result.Numbers.MinLength, MinLength);
end;

function TAlgosimNumericEntity.ConjugateTranspose: TAlgosimMatrix;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotConjTranspose, [ClassTypeName]);
end;

procedure TAlgosimNumericEntity.Defuzz(const Eps: Double);
begin

end;

function TAlgosimNumericEntity.GetDigitGrouping: Integer;
begin
  Result := Integer((FFormatCode and FCM_GROUP) shr 32);
end;

function TAlgosimNumericEntity.GetDigitGroupingOverride: Boolean;
begin
  Result := FFormatCode and FCM_GROUPO <> 0;
end;

function TAlgosimNumericEntity.GetMinLength: Integer;
begin
  Result := Byte((FFormatCode and FCM_MINLEN) shr 48);
end;

function TAlgosimNumericEntity.GetNumberBase: Integer;
begin
  Result := Integer((FFormatCode and FCM_BASE) shr 16);
end;

function TAlgosimNumericEntity.GetNumberFormat: TNumberFormat;
begin
  Result := TNumberFormat(
    EnsureRange(
      (FFormatCode and FCM_NUMFMT) shr 40,
      Ord(Low(TNumberFormat)),
      Ord(High(TNumberFormat))
    )
  );
end;

function TAlgosimNumericEntity.GetNumberFormatOverride: Boolean;
begin
  Result := FFormatCode and FCM_NUMFMTO <> 0;
end;

function TAlgosimNumericEntity.GetNumDigits: Integer;
begin
  Result := Integer(FFormatCode and FCM_DIGITS);
end;

function TAlgosimNumericEntity.GetNumDigitsOverride: Boolean;
begin
  Result := FFormatCode and FCM_DIGITSO <> 0;
end;

function TAlgosimNumericEntity.GetPrettyExp: Boolean;
begin
  Result := FFormatCode and FCM_EXPFMT <> 0;
end;

function TAlgosimNumericEntity.GetPrettyExpOverride: Boolean;
begin
  Result := FFormatCode and FCM_EXPFMTO <> 0;
end;

function TAlgosimNumericEntity.GetStyle: TFormatStyle;
begin
  Result := TFormatStyle(Byte((FFormatCode and FCM_STYLE) shr 24));
end;

function TAlgosimNumericEntity.ImaginaryPart: TAlgosimNumericEntity;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotComputeImgPart, [ClassTypeName]);
end;

function TAlgosimNumericEntity.Inverse: TAlgosimNumericEntity;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotInvert, [ClassTypeName]);
end;

function TAlgosimNumericEntity.IsNegative(const Eps: Double): Boolean;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotDetermineSign, [ClassTypeName]);
end;

function TAlgosimNumericEntity.IsNonNegative(const Eps: Double): Boolean;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotDetermineSign, [ClassTypeName]);
end;

function TAlgosimNumericEntity.IsNonPositive(const Eps: Double): Boolean;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotDetermineSign, [ClassTypeName]);
end;

function TAlgosimNumericEntity.IsNonZero(const Eps: Double): Boolean;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotDetermineSign, [ClassTypeName]);
end;

function TAlgosimNumericEntity.IsPositive(const Eps: Double): Boolean;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotDetermineSign, [ClassTypeName]);
end;

function TAlgosimNumericEntity.IsZero(const Eps: Double): Boolean;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotDetermineSign, [ClassTypeName]);
end;

function TAlgosimNumericEntity.Norm(AType: TNormType; AParam: Integer;
  AYieldProc: TObjProc): TASR;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotComputeNorm, [NormTypes[AType], ClassTypeName]);
end;

function TAlgosimNumericEntity.NormSquared: TAlgosimRealNumber;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotNormSquare, [ClassTypeName]);
end;

function TAlgosimNumericEntity.RealPart: TAlgosimNumericEntity;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotComputeRePart, [ClassTypeName]);
end;

function TAlgosimNumericEntity.ScaledBy(const AFactor: TASR): TAlgosimNumericEntity;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotScale, [ClassTypeName]);
end;

procedure TAlgosimNumericEntity.SetDigitGrouping(Value: Integer);
begin
  if not InRange(Value, 0, 127) then
    raise EAlgosimObjectException.CreateFmt(SInvDigGrSize, [Value]);
  FFormatCode := (FFormatCode and not FCM_GROUP) or ((UInt64(Value) shl 32) and FCM_GROUP);
end;

procedure TAlgosimNumericEntity.SetDigitGroupingOverride(Value: Boolean);
begin
  if Value then
    FFormatCode := FFormatCode or FCM_GROUPO
  else
    FFormatCode := FFormatCode and not FCM_GROUPO;
end;

procedure TAlgosimNumericEntity.SetMinLength(Value: Integer);
begin
  if not InRange(Value, 0, 255) then
    raise EAlgosimObjectException.CreateFmt(SInvMinLen, [Value]);
  FFormatCode := (FFormatCode and not FCM_MINLEN) or ((UInt64(Value) shl 48) and FCM_MINLEN);
end;

procedure TAlgosimNumericEntity.SetNumberBase(Value: Integer);
begin
  if (Value <> 0) and not InRange(Value, 2, 36) then
    raise EAlgosimObjectException.CreateFmt(SInvNumberBase, [Value]);
  FFormatCode := (FFormatCode and not FCM_BASE) or ((Byte(Value) shl 16) and FCM_BASE);
end;

procedure TAlgosimNumericEntity.SetNumberFormat(Value: TNumberFormat);
begin
  if not InRange(Ord(Value), 0, 3) then
    Value := nfDefault;
  FFormatCode := (FFormatCode and not FCM_NUMFMT) or ((UInt64(Ord(Value)) shl 40) and FCM_NUMFMT);
end;

procedure TAlgosimNumericEntity.SetNumberFormatOverride(Value: Boolean);
begin
  if Value then
    FFormatCode := FFormatCode or FCM_NUMFMTO
  else
    FFormatCode := FFormatCode and not FCM_NUMFMTO;
end;

procedure TAlgosimNumericEntity.SetNumDigits(const Value: Integer);
begin
  if not InRange(Value, 0, 32767) then
    raise EAlgosimObjectException.CreateFmt(SInvNumDigits, [Value]);
  FFormatCode := (FFormatCode and not FCM_DIGITS) or (Word(Value) and FCM_DIGITS);
end;

procedure TAlgosimNumericEntity.SetNumDigitsOverride(const Value: Boolean);
begin
  if Value then
    FFormatCode := FFormatCode or FCM_DIGITSO
  else
    FFormatCode := FFormatCode and not FCM_DIGITSO;
end;

procedure TAlgosimNumericEntity.SetPrettyExp(Value: Boolean);
begin
  if Value then
    FFormatCode := FFormatCode or FCM_EXPFMT
  else
    FFormatCode := FFormatCode and not FCM_EXPFMT;
end;

procedure TAlgosimNumericEntity.SetPrettyExpOverride(Value: Boolean);
begin
  if Value then
    FFormatCode := FFormatCode or FCM_EXPFMTO
  else
    FFormatCode := FFormatCode and not FCM_EXPFMTO;
end;

procedure TAlgosimNumericEntity.SetStyle(const Value: TFormatStyle);
begin
  FFormatCode := (FFormatCode and not FCM_STYLE) or (Byte(Ord(Value)) shl 24);
end;

function TAlgosimNumericEntity.Square: TAlgosimNumericEntity;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotSquare, [ClassTypeName]);
end;

function TAlgosimNumericEntity.Transpose: TAlgosimMatrix;
begin
  raise EAlgosimObjectException.CreateFmt(SCannotTranspose, [ClassTypeName]);
end;

{ TAlgosimNumber }

procedure TAlgosimNumber.AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer);
begin
  AArray.Add(Self.Clone);
end;

class function TAlgosimNumber.Divide(Left,
  Right: TAlgosimNumber): TAlgosimNumber;
begin
  Result := Right.DivideBy(Left);
end;

function TAlgosimNumber.Equals(Obj: TObject): Boolean;
var
  Num: TAlgosimNumber absolute Obj;
begin
  Result := Obj is TAlgosimNumber;
  if Result then
    if Self.IsComplex or Num.IsComplex then
      Result := Self.ToASC = Num.ToASC
    else
      Result := Self.ToASR = Num.ToASR;
end;

class function TAlgosimNumber.Multiply(Left,
  Right: TAlgosimNumber): TAlgosimNumber;
begin
  Result := Right.MultiplyTo(Left);
end;

class function TAlgosimNumber.Power(Left,
  Right: TAlgosimNumber): TAlgosimNumber;
begin
  Result := Right.RaiseTo(Left);
end;

procedure TAlgosimNumber.SetMaxLen(AValue: Integer);
begin
  NumDigitsOverride := True;
  NumDigits := AValue;
end;

class function TAlgosimNumber.SortClass: TSortClass;
begin
  Result := SORTCLASS_NUMBER;
end;

class function TAlgosimNumber.SortClassCompare(const Left,
  Right: TAlgosimObject): Integer;
begin
  if Left.IsComplex or Right.IsComplex then
    Result := CompareValue(Left.ToASC, Right.ToASC)
  else
    Result := CompareValue(Left.ToASR, Right.ToASR);
end;

class function TAlgosimNumber.SortClassSameObject(const Left,
  Right: TAlgosimObject; const AEpsilon: TASR): Boolean;
begin
  if Left.IsComplex or Right.IsComplex then
    Result := CSameValue(Left.ToASC, Right.ToASC, AEpsilon)
  else
    Result := SameValue(Left.ToASR, Right.ToASR, AEpsilon);
end;

class function TAlgosimNumber.Subtract(Left,
  Right: TAlgosimNumber): TAlgosimNumber;
begin
  Result := Right.SubtractFrom(Left);
end;

function TAlgosimNumber.ToColor: TRGB;
var
  intval: Integer;
begin
  if TryToInt32(intval) then
    if intval > 0 then
      Result := TRGB(TColor(RBSwap(intval)))
    else
      Result := TRGB(ColorToRGB(TColor(intval)))
  else
    raise EAlgosimObjectException.Create(SConvNonIntColor);
end;

class function TAlgosimNumber.Add(Left,
  Right: TAlgosimNumber): TAlgosimNumber;
begin
  Result := Right.AddTo(Left);
end;

class function TAlgosimNumber.LessThan(Left: TAlgosimNumber;
  Right: TAlgosimNumber): Boolean;
begin

  if Left.IsComplex or Right.IsComplex then
    raise EAlgosimObjectException.Create(SCmplxNoOrder);

  if (Left is TAlgosimInteger) and (Right is TAlgosimInteger) then
    Result := TAlgosimInteger(Left).Value < TAlgosimInteger(Right).Value
  else
    Result := Left.ToASR < Right.ToASR;

end;

class function TAlgosimNumber.LessThanOrEqualTo(Left: TAlgosimNumber;
  Right: TAlgosimNumber): Boolean;
begin

  if Left.IsComplex or Right.IsComplex then
    raise EAlgosimObjectException.Create(SCmplxNoOrder);

  if (Left is TAlgosimInteger) and (Right is TAlgosimInteger) then
    Result := TAlgosimInteger(Left).Value <= TAlgosimInteger(Right).Value
  else
    Result := Left.ToASR <= Right.ToASR;

end;

function TAlgosimNumber.SortClassGetHashCode: Integer;
var
  X: TASR;
begin
  // (TAlgosimComplexNumber overrides SortClassGetHashCode)
  X := Self.ToASR;
  Result := THashBobJenkins.GetHashValue(X, sizeof(X));
end;

function TAlgosimNumber.GetMaxLen: Integer;
begin
  Result := NumDigits;
end;

class function TAlgosimNumber.GreaterThan(Left: TAlgosimNumber;
  Right: TAlgosimNumber): Boolean;
begin

  if Left.IsComplex or Right.IsComplex then
    raise EAlgosimObjectException.Create(SCmplxNoOrder);

  if (Left is TAlgosimInteger) and (Right is TAlgosimInteger) then
    Result := TAlgosimInteger(Left).Value > TAlgosimInteger(Right).Value
  else
    Result := Left.ToASR > Right.ToASR;

end;

class function TAlgosimNumber.GreaterThanOrEqualTo(Left: TAlgosimNumber;
  Right: TAlgosimNumber): Boolean;
begin

  if Left.IsComplex or Right.IsComplex then
    raise EAlgosimObjectException.Create(SCmplxNoOrder);

  if (Left is TAlgosimInteger) and (Right is TAlgosimInteger) then
    Result := TAlgosimInteger(Left).Value >= TAlgosimInteger(Right).Value
  else
    Result := Left.ToASR >= Right.ToASR;

end;

{ TAlgosimRealNumber }

function TAlgosimRealNumber.Abs: TAlgosimNumericEntity;
begin
  Result := ASO(System.Abs(FValue));
end;

function TAlgosimRealNumber.AddASC(ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(TASC(FValue) + ASC.Value);
end;

function TAlgosimRealNumber.AddASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue + TASR(ASI.Value));
end;

function TAlgosimRealNumber.AddRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue + TASR(R.Value));
end;

function TAlgosimRealNumber.AddASR(ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue + ASR.Value);
end;

function TAlgosimRealNumber.AddTo(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.AddASR(Self);
end;

function TAlgosimRealNumber.Argument: TAlgosimRealNumber;
begin
  if FValue >= 0 then
    Result := ASO(0)
  else
    Result := ASO(Pi);
end;

function TAlgosimRealNumber.AsMemberOfSimplestField: TAlgosimNumber;
begin
  Result := TAlgosimRealNumber(Clone);
end;

function TAlgosimRealNumber.ComputeFunction(const ARealDomain: TSDD;
  ARealFcn: TRealFunction; AComplexFcn: TComplexFunction): TAlgosimNumber;
begin
  if ARealDomain.Contains(Value) then
    Result := ASO(ARealFcn(Value))
  else
    Result := ASO(AComplexFcn(Value));
end;

function TAlgosimRealNumber.ComputeFunction(ARealFcn: TRealFunction;
  AComplexFcn: TComplexFunction): TAlgosimNumber;
begin
  Result := ASO(ARealFcn(Value));
end;

function TAlgosimRealNumber.Conjugate: TAlgosimNumber;
begin
  Result := TAlgosimNumber(Clone);
end;

constructor TAlgosimRealNumber.Create(AObject: TAlgosimObject);
begin
  CreateWithValue(AObject.ToRealNumber);
  if AObject is TAlgosimNumericEntity then
    FormatCode := TAlgosimNumericEntity(AObject).FormatCode;
end;

constructor TAlgosimRealNumber.CreateWithValue(const AValue: TASR);
begin
  Create;
  FValue := AValue;
end;

procedure TAlgosimRealNumber.Defuzz(const Eps: Double);
begin
  if IsInteger(FValue, Eps) then
    FValue := Round(FValue);
end;

function TAlgosimRealNumber.DivideASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(TASC(FValue) / ASC.Value);
end;

function TAlgosimRealNumber.DivideASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue / TASR(ASI.Value));
end;

function TAlgosimRealNumber.DivideRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue / TASR(R.Value));
end;

function TAlgosimRealNumber.ExplainedOutput(
  const AOptions: TFormatOptions): string;
var
  SSF: TSimpleSymbolicForm;
begin
  Result := GetAsSingleLineText(AOptions);
  if (Style = fsDefault) and not IsInteger(FValue) then
  begin
    SSF := ToSymbolicForm(FValue);
    if SSF.valid and SameValue2(TASR(SSF), FValue) then
      Result := Result + #9 + '(=' + SSF.ToString(ApplyOptions(AOptions)) + ')'
  end;
end;

function TAlgosimRealNumber.DivideASR(ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue / ASR.Value);
end;

function TAlgosimRealNumber.DivideBy(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.DivideASR(Self);
end;

function TAlgosimRealNumber.GetAsSingleLineText(const AOptions: TFormatOptions): string;
var
  Formatter: TASRFormatter;
begin

  if (Style <> fsDefault) and TryGetFormatter(Style, Formatter) then
    Result := Formatter(ApplyOptions(AOptions), FValue)
  else
    Result := ASNum.RealToStr(FValue, ApplyOptions(AOptions));

end;

function TAlgosimRealNumber.GetBinaryData(var Buf: PByte;
  var Len: UInt64): Boolean;
begin
  Buf := @FValue;
  Len := sizeof(FValue);
  Result := True;
end;

function TAlgosimRealNumber.GetMemorySize: UInt64;
begin
  Result := sizeof(FValue);
end;

function TAlgosimRealNumber.ImaginaryPart: TAlgosimNumericEntity;
begin
  Result := ASO(0);
end;

procedure TAlgosimRealNumber.Increase(AAmount: TASI);
begin
  FValue := FValue + AAmount;
end;

function TAlgosimRealNumber.Inverse: TAlgosimNumericEntity;
begin
  Result := ASO(1.0 / Value);
end;

function TAlgosimRealNumber.IsNegative(const Eps: Double): Boolean;
begin
  Result := (FValue < 0) and not Math.IsZero(FValue, Eps);
end;

function TAlgosimRealNumber.IsNonNegative(const Eps: Double): Boolean;
begin
  Result := (FValue > 0) or Math.IsZero(FValue, Eps);
end;

function TAlgosimRealNumber.IsNonPositive(const Eps: Double): Boolean;
begin
  Result := (FValue < 0) or Math.IsZero(FValue, Eps);
end;

function TAlgosimRealNumber.IsNonZero(const Eps: Double): Boolean;
begin
  Result := not Math.IsZero(FValue, Eps);
end;

function TAlgosimRealNumber.IsPositive(const Eps: Double): Boolean;
begin
  Result := (FValue > 0) and not Math.IsZero(FValue, Eps);
end;

function TAlgosimRealNumber.IsZero(const Eps: Double): Boolean;
begin
  Result := Math.IsZero(FValue, Eps);
end;

function TAlgosimRealNumber.MultiplyASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(TASC(FValue) * ASC.Value);
end;

function TAlgosimRealNumber.MultiplyASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue * TASR(ASI.Value));
end;

function TAlgosimRealNumber.MultiplyRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue * TASR(R.Value));
end;

function TAlgosimRealNumber.MultiplyASR(
  ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue * ASR.Value);
end;

function TAlgosimRealNumber.MultiplyTo(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.MultiplyASR(Self);
end;

function TAlgosimRealNumber.Norm(AType: TNormType; AParam: Integer;
  AYieldProc: TObjProc): TASR;
begin
  Result := System.Abs(FValue);
end;

function TAlgosimRealNumber.NormSquared: TAlgosimRealNumber;
begin
  Result := ASO(System.Sqr(FValue));
end;

function TAlgosimRealNumber.RaiseTo(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.RaiseToASR(Self);
end;

function TAlgosimRealNumber.RaiseToASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(cpow(TASC(FValue), ASC.Value));
end;

function TAlgosimRealNumber.RaiseToASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(pow(FValue, TASR(ASI.Value)));
end;

function TAlgosimRealNumber.RaiseToRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  if (FValue < 0) and (R.Value.Denominator <> 1) then
    Result := ASO(cpow(TASC(FValue), TASC(TASR(R.FValue))))
  else
    Result := ASO(pow(FValue, TASR(R.Value)));
end;

function TAlgosimRealNumber.RaiseToASR(ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  if (FValue < 0) and not ASNum.IsInteger(ASR.Value) then
    Result := ASO(cpow(FValue, ASR.Value))
  else
    Result := ASO(pow(FValue, ASR.Value));
end;

function TAlgosimRealNumber.RealPart: TAlgosimNumericEntity;
begin
  result := ASO(FValue);
end;

function TAlgosimRealNumber.ScaledBy(
  const AFactor: TASR): TAlgosimNumericEntity;
begin
  Result := ASO(FValue * AFactor);
end;

procedure TAlgosimRealNumber.SetBinaryData(const Buf: PByte; const Len: UInt64);
begin
  if Len = sizeof(TASR) then
    FValue := PASR(Buf)^
  else
    raise EAlgosimObjectException.CreateFmt(SInvalidBlob, [ClassTypeName]);
end;

function TAlgosimRealNumber.Square: TAlgosimNumericEntity;
begin
  Result := ASO(Value * Value);
end;

function TAlgosimRealNumber.SubtractASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(TASC(FValue) - ASC.Value);
end;

function TAlgosimRealNumber.SubtractASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue - TASR(ASI.Value));
end;

function TAlgosimRealNumber.SubtractRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue - TASR(R.Value));
end;

function TAlgosimRealNumber.SubtractASR(
  ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue - ASR.Value);
end;

function TAlgosimRealNumber.SubtractFrom(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.SubtractASR(Self);
end;

function TAlgosimRealNumber.ToBoolean: Boolean;
begin
  Result := Value <> 0;
end;

function TAlgosimRealNumber.ToComplexMatrix: TComplexMatrix;
begin
  Result := TComplexMatrix.Create([Value]);
end;

function TAlgosimRealNumber.ToComplexNumber: TASC;
begin
  Result := FValue;
end;

function TAlgosimRealNumber.ToComplexVector: TComplexVector;
begin
  Result := TComplexVector.Create([Value]);
end;

function TAlgosimRealNumber.ToRealMatrix: TRealMatrix;
begin
  Result := TRealMatrix.Create([Value]);
end;

function TAlgosimRealNumber.ToRealNumber: TASR;
begin
  Result := Value;
end;

function TAlgosimRealNumber.ToRealVector: TRealVector;
begin
  Result := TRealVector.Create([Value]);
end;

function TAlgosimRealNumber.ToSpeech: string;
begin
  Result := RealToStr(FValue, DefaultFormatOptions)
    .Replace('E', ' times ', [rfIgnoreCase, rfReplaceAll])
    .Replace(MINUS_SIGN, ' negative ', [rfReplaceAll])
    .Replace(HYPHEN_MINUS, ' negative ', [rfReplaceAll])
    .Replace(DOT_OPERATOR, ' times ', [rfReplaceAll])
    .Replace('^', ' raised to the power of ', [rfReplaceAll])
end;

function TAlgosimRealNumber.ToString: string;
begin
  Result := RealToStr(FValue, ExchangeFormOptions);
end;

function TAlgosimRealNumber.TryToASI(out ASI: Int64): Boolean;
begin
  Result := ASNum.IsInteger(FValue);
  if Result then
    ASI := Round(FValue);
end;

function TAlgosimRealNumber.TryToRat(out R: TRationalNumber): Boolean;
begin
  try
    R := ASNum.ToFraction(FValue);
    Result := True;
  except
    Result := False;
  end;
end;

function TAlgosimRealNumber.TryToASR(out Val: TASR): Boolean;
begin
  Result := True;
  Val := FValue;
end;

function TAlgosimRealNumber.TryToASC(out Val: TASC): Boolean;
begin
  Result := True;
  Val := FValue;
end;

function TAlgosimRealNumber.TryToInt32(out Int: Integer): Boolean;
begin
  Result := ASNum.IsInteger32(FValue);
  if Result then
    Int := Round(FValue);
end;

function TAlgosimRealNumber.TryToInt64(out Int: Int64): Boolean;
begin
  Result := ASNum.IsInteger64(FValue);
  if Result then
    Int := Round(FValue);
end;

function TAlgosimRealNumber.UnaryMinus: TAlgosimObject;
begin
  Result := ASO(-FValue);
end;

{ TAlgosimComplexNumber }

function TAlgosimComplexNumber.Abs: TAlgosimNumericEntity;
begin
  Result := ASO(FValue.Modulus);
end;

function TAlgosimComplexNumber.AddASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(FValue + ASC.Value);
end;

function TAlgosimComplexNumber.AddASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue + TASC(TASR(ASI.Value)));
end;

function TAlgosimComplexNumber.AddRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue + TASC(TASR(R.Value)));
end;

function TAlgosimComplexNumber.AddASR(ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue + TASC(ASR.Value));
end;

function TAlgosimComplexNumber.AddTo(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.AddASC(Self);
end;

function TAlgosimComplexNumber.Argument: TAlgosimRealNumber;
begin
  Result := ASO(FValue.Argument);
end;

function TAlgosimComplexNumber.AsMemberOfSimplestField: TAlgosimNumber;
begin
  if FValue.IsReal then
    Result := TAlgosimRealNumber.CreateWithValue(FValue.Re)
  else
    Result := TAlgosimComplexNumber(Clone);
end;

function TAlgosimComplexNumber.ComputeFunction(const ARealDomain: TSDD;
  ARealFcn: TRealFunction; AComplexFcn: TComplexFunction): TAlgosimNumber;
begin
  Result := ASO(AComplexFcn(Value));
end;

function TAlgosimComplexNumber.ComputeFunction(ARealFcn: TRealFunction;
  AComplexFcn: TComplexFunction): TAlgosimNumber;
begin
  Result := ASO(AComplexFcn(Value));
end;

function TAlgosimComplexNumber.Conjugate: TAlgosimNumber;
begin
  Result := ASO(FValue.Conjugate);
end;

constructor TAlgosimComplexNumber.Create(AObject: TAlgosimObject);
begin
  CreateWithValue(AObject.ToComplexNumber);
  if AObject is TAlgosimNumericEntity then
    Self.FormatCode := TAlgosimNumericEntity(AObject).FormatCode;
end;

constructor TAlgosimComplexNumber.CreateWithValue(const AValue: TASC);
begin
  Create;
  FValue := AValue;
end;

procedure TAlgosimComplexNumber.Defuzz(const Eps: Double);
begin
  Value := Value.Defuzz(Eps);
end;

function TAlgosimComplexNumber.DivideASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(FValue / ASC.Value);
end;

function TAlgosimComplexNumber.DivideASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue / TASC(TASR(ASI.Value)));
end;

function TAlgosimComplexNumber.DivideRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue / TASC(TASR(R.Value)));
end;

function TAlgosimComplexNumber.DivideASR(
  ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue / TASC(ASR.Value));
end;

function TAlgosimComplexNumber.DivideBy(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.DivideASC(Self);
end;

function TAlgosimComplexNumber.GetAsSingleLineText(const AOptions: TFormatOptions): string;
begin
  Result := ComplexToStr(FValue, False, ApplyOptions(AOptions));
end;

function TAlgosimComplexNumber.GetBinaryData(var Buf: PByte;
  var Len: UInt64): Boolean;
begin
  Buf := @FValue;
  Len := sizeof(FValue);
  Result := True;
end;

function TAlgosimComplexNumber.GetMemorySize: UInt64;
begin
  Result := sizeof(FValue);
end;

function TAlgosimComplexNumber.SortClassGetHashCode: Integer;
begin
  if FValue.Im = 0 then
    Result := THashBobJenkins.GetHashValue(FValue.Re, sizeof(FValue.Re))
  else
    Result := THashBobJenkins.GetHashValue(FValue, sizeof(FValue))
end;

function TAlgosimComplexNumber.ImaginaryPart: TAlgosimNumericEntity;
begin
  Result := ASO(FValue.Im);
end;

procedure TAlgosimComplexNumber.Increase(AAmount: TASI);
begin
  FValue := FValue + AAmount;
end;

function TAlgosimComplexNumber.Inverse: TAlgosimNumericEntity;
begin
  Result := ASO(Value.Inverse);
end;

function TAlgosimComplexNumber.IsNonZero(const Eps: Double): Boolean;
begin
  Result := not CIsZero(FValue, Eps);
end;

function TAlgosimComplexNumber.IsZero(const Eps: Double): Boolean;
begin
  Result := CIsZero(FValue, Eps);
end;

function TAlgosimComplexNumber.MultiplyASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(FValue * ASC.Value);
end;

function TAlgosimComplexNumber.MultiplyASI(
  ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue * TASC(TASR(ASI.Value)));
end;

function TAlgosimComplexNumber.MultiplyRat(
  R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue * TASC(TASR(R.Value)));
end;

function TAlgosimComplexNumber.MultiplyASR(
  ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue * TASC(ASR.Value));
end;

function TAlgosimComplexNumber.MultiplyTo(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.MultiplyASC(Self);
end;

function TAlgosimComplexNumber.Norm(AType: TNormType; AParam: Integer;
  AYieldProc: TObjProc): TASR;
begin
  Result := FValue.Modulus;
end;

function TAlgosimComplexNumber.NormSquared: TAlgosimRealNumber;
begin
  Result := ASO(FValue.ModSqr);
end;

function TAlgosimComplexNumber.RaiseTo(ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.RaiseToASC(Self);
end;

function TAlgosimComplexNumber.RaiseToASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(cpow(FValue, ASC.Value));
end;

function TAlgosimComplexNumber.RaiseToASI(ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(cpow(FValue, TASC(TASR(ASI.Value))));
end;

function TAlgosimComplexNumber.RaiseToRat(R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(cpow(FValue, TASC(TASR(R.Value))));
end;

function TAlgosimComplexNumber.RaiseToASR(
  ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(cpow(FValue, TASC(ASR.Value)));
end;

function TAlgosimComplexNumber.RealPart: TAlgosimNumericEntity;
begin
  Result := ASO(FValue.Re);
end;

function TAlgosimComplexNumber.ScaledBy(
  const AFactor: TASR): TAlgosimNumericEntity;
begin
  Result := ASO(FValue * AFactor);
end;

procedure TAlgosimComplexNumber.SetBinaryData(const Buf: PByte;
  const Len: UInt64);
begin
  if Len = sizeof(TASC) then
    FValue := PASC(Buf)^
  else
    raise EAlgosimObjectException.CreateFmt(SInvalidBlob, [ClassTypeName]);
end;

function TAlgosimComplexNumber.Square: TAlgosimNumericEntity;
begin
  Result := ASO(Value.Sqr);
end;

function TAlgosimComplexNumber.SubtractASC(
  ASC: TAlgosimComplexNumber): TAlgosimNumber;
begin
  Result := ASO(FValue - ASC.Value);
end;

function TAlgosimComplexNumber.SubtractASI(
  ASI: TAlgosimInteger): TAlgosimNumber;
begin
  Result := ASO(FValue - TASC(TASR(ASI.Value)));
end;

function TAlgosimComplexNumber.SubtractRat(
  R: TAlgosimRationalNumber): TAlgosimNumber;
begin
  Result := ASO(FValue - TASC(TASR(R.Value)));
end;

function TAlgosimComplexNumber.SubtractASR(
  ASR: TAlgosimRealNumber): TAlgosimNumber;
begin
  Result := ASO(FValue - TASC(ASR.Value));
end;

function TAlgosimComplexNumber.SubtractFrom(
  ANum: TAlgosimNumber): TAlgosimNumber;
begin
  Result := ANum.SubtractASC(Self);
end;

function TAlgosimComplexNumber.ToBoolean: Boolean;
begin
  Result := Value <> ComplexZero;
end;

function TAlgosimComplexNumber.ToComplexMatrix: TComplexMatrix;
begin
  Result := TComplexMatrix.Create([Value]);
end;

function TAlgosimComplexNumber.ToComplexNumber: TASC;
begin
  Result := Value;
end;

function TAlgosimComplexNumber.ToComplexVector: TComplexVector;
begin
  Result := TComplexVector.Create([Value]);
end;

function TAlgosimComplexNumber.ToRealMatrix: TRealMatrix;
begin
  if Value.IsReal then
    Result := TRealMatrix.Create([Value.Re])
  else
    raise EAlgosimObjectException.CreateFmt(SConvComplexReal, [Value.pstr]);
end;

function TAlgosimComplexNumber.ToRealNumber: TASR;
begin
  if Value.IsReal then
    result := Value.Re
  else
    raise EAlgosimObjectException.CreateFmt(SConvComplexReal, [Value.pstr]);
end;

function TAlgosimComplexNumber.ToRealVector: TRealVector;
begin
  Result := TRealVector.Create([Value.Re, Value.Im]);
end;

function TAlgosimComplexNumber.ToString: string;
begin
  Result := ComplexToStr(FValue, False, ExchangeFormOptions);
end;

function TAlgosimComplexNumber.TryToASI(out ASI: Int64): Boolean;
begin
  Result := FValue.IsReal and ASNum.IsInteger(FValue.Re);
  if Result then
    ASI := Round(FValue.Re);
end;

function TAlgosimComplexNumber.TryToRat(out R: TRationalNumber): Boolean;
begin
  Result := FValue.IsReal and ASNum.IsInteger(FValue.Re);
  if Result then
    R := Round(FValue.Re);
end;

function TAlgosimComplexNumber.TryToASR(out Val: TASR): Boolean;
begin
  Result := FValue.IsReal;
  if Result then
    Val := FValue.Re;
end;

function TAlgosimComplexNumber.TryToASC(out Val: TASC): Boolean;
begin
  Result := True;
  Val := FValue;
end;

function TAlgosimComplexNumber.TryToInt32(out Int: Integer): Boolean;
begin
  Result := FValue.IsReal and ASNum.IsInteger32(FValue.Re);
  if Result then
    Int := Round(FValue.Re);
end;

function TAlgosimComplexNumber.TryToInt64(out Int: Int64): Boolean;
begin
  Result := FValue.IsReal and ASNum.IsInteger64(FValue.Re);
  if Result then
    Int := Round(FValue.Re);
end;

function TAlgosimComplexNumber.UnaryMinus: TAlgosimObject;
begin
  Result := ASO(-FValue);
end;

{ TAlgosimString }

function TAlgosimString.Accumulate(AInitialValue: TAlgosimObject;
  AFunction: TASOAccumulator): TAlgosimObject;
var
  i: Integer;
  char: TAlgosimString;
begin
  char := TAlgosimString.CreateWithValue('a');
  try
    Result := AInitialValue.Clone;
    try
      for i := 1 to FValue.Length do
      begin
        char.FValue[1] := FValue[i];
        TObjReplacer<TAlgosimObject>.Replace(Result, AFunction(Result, char));
      end;
    except
      Result.Free;
      raise;
    end;
  finally
    char.Free;
  end;
end;

function TAlgosimString.AccumulateStepsList(AInitialValue: TAlgosimObject;
  AFunction: TASOAccumulator): TAlgosimArray;
var
  i: Integer;
  char: TAlgosimString;
begin
  char := TAlgosimString.CreateWithValue('a');
  try
    Result := TAlgosimArray.Create;
    try
      Result.Capacity := FValue.Length;
      for i := 1 to FValue.Length do
      begin
        char.FValue[1] := FValue[i];
        AInitialValue := AFunction(AInitialValue, char);
        Result.Add(AInitialValue);
      end;
    except
      Result.Free;
      raise;
    end;
  finally
    char.Free;
  end;
end;

procedure TAlgosimString.AddNumbersToArray(AArray: TAlgosimArray; ALevel: Integer);
begin

end;

procedure TAlgosimString.Append(AElement: TAlgosimObject);
begin
  try
    FValue := FValue + AElement.ToCharacter;
  finally
    AElement.Free;
  end;
end;

procedure TAlgosimString.Apply(AFunction: TASOFunction;
  ACondition: TASOPredicate; ALevel: Integer);
var
  i: Integer;
  char: TAlgosimString;
  res: TAlgosimObject;
begin

  if ALevel > 1 then
    Exit;

  char := TAlgosimString.CreateWithValue('a');
  try
    for i := 1 to FValue.Length do
    begin
      char.FValue[1] := FValue[i];
      if not Assigned(ACondition) or ACondition(char) then
      begin
        res := AFunction(char);
        try
          if IsCharacter(res) then
            FValue[i] := TAlgosimString(res).Value[1]
          else
            raise EAlgosimObjectException.Create(SCharApply);
        finally
          res.Free;
        end;
      end;
    end;
  finally
    char.Free;
  end;

end;

procedure TAlgosimString.ExtendWith(AElement: TAlgosimObject);
begin
  try
    FValue := FValue + AElement.ToString;
  finally
    AElement.Free;
  end;
end;

class function TAlgosimString.Concat(
  const Args: array of TAlgosimString): TAlgosimString;
var
  len: Integer;
  i, j: Integer;
  S: string;
begin
  len := 0;
  for i := 0 to High(Args) do
    Inc(len, Args[i].FValue.Length);
  SetLength(S, len);
  j := 1;
  for i := 0 to High(Args) do
    if not Args[i].FValue.IsEmpty then
    begin
      Move(Args[i].FValue[1], S[j], Args[i].FValue.Length * sizeof(Char));
      Inc(j, Args[i].FValue.Length);
    end;
  Result := ASO(S);
end;

function TAlgosimString.Count(APredicate: TASOPredicate): Integer;
var
  i: Integer;
  char: TAlgosimString;
begin
  char := TAlgosimString.CreateWithValue('a');
  try
    Result := 0;
    for i := 1 to FValue.Length do
    begin
      char.FValue[1] := FValue[i];
      if APredicate(char) then
        Inc(Result);
    end;
  finally
    char.Free;
  end;
end;

constructor TAlgosimString.Create(AObject: TAlgosimObject);
begin
  CreateWithValue(AObject.ToString);
end;

constructor TAlgosimString.CreateWithValue(const AValue: string);
begin
  Create;
  FValue := AValue;
end;

function TAlgosimString.Equals(Obj: TObject): Boolean;
begin
  Result := (Obj is TAlgosimString) and (Value = TAlgosimString(Obj).Value);
end;

function TAlgosimString.Exists(APredicate: TASOPredicate): Boolean;
var
  i: Integer;
  char: TAlgosimString;
begin
  char := TAlgosimString.CreateWithValue('a');
  try
    for i := 1 to FValue.Length do
    begin
      char.FValue[1] := FValue[i];
      if APredicate(char) then
        Exit(True);
    end;
    Result := False;
  finally
    char.Free;
  end;
end;

function TAlgosimString.Filter(APredicate: TASOPredicate): TAlgosimObject;
var
  S: string;
  i, j: Integer;
  char: TAlgosimString;
begin
  SetLength(S, FValue.Length);
  j := 1;
  char := TAlgosimString.CreateWithValue('a');
  try
    for i := 1 to FValue.Length do
    begin
      char.FValue[1] := FValue[i];
      if APredicate(char) then
      begin
        S[j] := char.FValue[1];
        Inc(j);
      end;
    end;
  finally
    char.Free;
  end;
  SetLength(S, j - 1);
  Exit(ASO(S));
end;

function TAlgosimString.First(N: Integer): TAlgosimObject;
begin
  Result := ASO(Copy(Value, 1, N));
end;

function TAlgosimString.ForAll(APredicate: TASOPredicate): Boolean;
var
  i: Integer;
  char: TAlgosimString;
begin
  char := TAlgosimString.CreateWithValue('a');
  try
    for i := 1 to FValue.Length do
    begin
      char.FValue[1] := FValue[i];
      if not APredicate(char) then
        Exit(False);
    end;
    Result := True;
  finally
    char.Free;
  end;
end;

function TAlgosimString.GetAsMultilineText(const AOptions: TFormatOptions): string;
var
  EffectiveMaxLen: Integer;
begin
  if FMaxLen > 0 then
    EffectiveMaxLen := FMaxLen
  else
    EffectiveMaxLen := AOptions.Strings.MaxLen;
  if Length(FValue) > EffectiveMaxLen then
    Result := Copy(FValue, 1, EffectiveMaxLen) + EllipsisSymbol_HORIZONTAL_ELLIPSIS
  else
    Result := FValue;
  if AOptions.Strings.Quoted then
    Result := '"'