Скачиваний:
31
Добавлен:
01.05.2014
Размер:
19 Кб
Скачать
unit Attribute;

interface

  uses
    Classes,
    DmmConstants,
    DmmTypes,
    FastVector,
    StandardSerializableObject,
    SysUtils,
    Utils;

  type
    {Класс,который хранит сведения о номинальном атрибуте}
    TDMNominalAttributeValue = class;
    
    {Класс итератор для перебора значений типа TDMNominalAttributeValue}
    TDMNominalAttributeValueEnumeration = class;

    {Класс, который хранит сведения об аттрибуте}
    TDMAttribute = class( TDMStandardSerializableObject )
    protected
      m_Name : AnsiString;
      m_Type : Integer;
      m_Values : TDMFastVector;
      m_Index : Integer;
      m_Ordering : Integer;
      m_Weight : Double;
      m_LowerBound : Double;
      m_UpperBound : Double;
      m_IsRegular : Boolean;
      m_IsAveragable : Boolean;
      m_HasZeroPoint : Boolean;
      m_LowerBoundIsOpen : Boolean;
      m_UpperBoundIsOpen : Boolean;

    public
      constructor Create( attributeName : AnsiString ); overload;
      constructor Create( attributeName : AnsiString; attributeValues : TDMFastVector ); overload;

      function addStringValue( value : AnsiString ) : Integer; overload;
      function addStringValue( attribute : TDMAttribute; const index : Integer ) : Integer; overload;

      function numValues : Integer;
      function indexOfValue( value : AnsiString ) : Integer;
      function enumerateValues : TDMNominalAttributeValueEnumeration;
      function value( const valIndex : Integer ) : AnsiString;
      procedure delete( const valIndex : Integer );
      procedure setValue( const valIndex : Integer; value : AnsiString );

      function name : AnsiString;
      function index : Integer;
      function attributeType : Integer;
      function weight : Double;
      function ordering : Integer;
      procedure setName( name : AnsiString );

      procedure setIndex( const index : Integer );
      procedure setAttributeType( const attributeType : Integer );
      procedure setWeight( const weight : Double );
      procedure setOrdering( const ordering : Integer );

      function hasZeropoint : Boolean;
      function isAveragable : Boolean;
      function isRegular : Boolean;

      function isNominal : Boolean;
      function isNumeric : Boolean;
      function isString : Boolean;

      function isInRange( const value : Double ) : Boolean;

      function getLowerNumericBound : Double;
      function getUpperBumericBound : Double;
      procedure setUpperNumericBound( const upperBound : Double );
      procedure setLowerNumericBound( const lowerBound : Double );

      function lowerNumericBoundIsOpen : Boolean;
      function upperNumericBoundIsOpen : Boolean;

      function copyObject : TObject; override;
      function cloneObject : TObject; override;

      function equals( otherObject : TObject ) : Boolean; override;

      procedure serializeObject( ostream : TStream ); override;
      procedure deserializeObject( istream : TStream ); override;

      function toString : AnsiString; override;

      function attrType():integer;
      function getAttrType():AnsiString;

      constructor Create (attributeName : AnsiString; index : integer); overload;

      constructor Create (attributeName : AnsiString; attributeValues : TDMFastVector;
	                          index : integer); overload;
      destructor Destroy(); override;
    end;

    TDMNominalAttributeValueEnumeration = class( TDMFastVectorEnumeration )
    public
      constructor Create( attribute : TDMAttribute );

      function hasMoreElements : Boolean; override;
      function nextElement : TDMNominalAttributeValue; reintroduce;
    end;


    TDMNominalAttributeValue = class( TDMStandardSerializableObject )
    public
      m_Name : AnsiString;

      constructor Create( name : AnsiString );

      function cloneObject : TObject; override;
      function copyObject : TObject; override;
      function equals( otherObject : TObject ) : Boolean; override;
      function toString : AnsiString; override;

      procedure serializeObject( ostream : TStream ); override;
      procedure deserializeObject( istream : TStream ); override;
  end;

implementation

  constructor TDMAttribute.Create( attributeName : AnsiString );
  begin
    m_Type := ATTRIBUTE_TYPE_NUMERIC;
    m_Name := attributeName;
    m_Ordering := ATTRIBUTE_ORDERING_ORDERED;
    m_Index := -1;
    m_upperBoundIsOpen := true;
    m_lowerBoundIsOpen := true;
    m_IsRegular := true;
    m_HasZeroPoint := true;
    m_IsAveragable := true;
    m_Values := nil;
    m_Weight := 1.0;
  end;

  constructor TDMAttribute.Create( attributeName : AnsiString; attributeValues : TDMFastVector );
  begin
    if attributeValues = nil then
      m_Type := ATTRIBUTE_TYPE_STRING
    else
      m_Type := ATTRIBUTE_TYPE_NOMINAL;

    m_Ordering := ATTRIBUTE_ORDERING_ORDERED;

    m_Name := attributeName;
    m_Values := attributeValues.copyObject as TDMFastVector;
    m_Index := -1;
    m_IsRegular := false;
    m_HasZeroPoint := false;
    m_IsAveragable := false;
    m_Weight := 1.0;
  end;

  constructor TDMAttribute.Create (attributeName : AnsiString; index : integer);
  begin
    self.Create(attributeName);
    m_Index := index;
  end;

  constructor TDMAttribute.Create (attributeName : AnsiString; attributeValues : TDMFastVector;
	                          index : integer);
  begin
    self.Create(attributeName, attributeValues);
    m_Index := index;
  end;

  function TDMAttribute.attrType():integer;
  begin
    Result := m_Type;
  end;

  function TDMAttribute.getAttrType():AnsiString;
  begin
    Result := 'тип не определен';
    if m_Type = 1 then
      Result := 'числовой';
    if m_Type = 2 then
      Result := 'номинальный';
    if m_Type = 3 then
      Result := 'строковый';
    if m_Type = 4 then
      Result := 'дата';
  end;

  function TDMAttribute.name : AnsiString;
  begin
    Result := m_Name;
  end;

  function TDMAttribute.index : Integer;
  begin
    Result := m_Index;
  end;

  function TDMAttribute.attributeType : Integer;
  begin
    Result := m_Type;
  end;

  function TDMAttribute.weight : Double;
  begin
    Result := m_Weight;
  end;

  function TDMAttribute.hasZeropoint : Boolean;
  begin
    Result := m_HasZeroPoint;
  end;

  function TDMAttribute.isAveragable : Boolean;
  begin
    Result := m_IsAveragable;
  end;

  function TDMAttribute.isRegular : Boolean;
  begin
    Result := m_IsRegular;
  end;

  function TDMAttribute.isNominal : Boolean;
  begin
    Result := m_Type = ATTRIBUTE_TYPE_NOMINAL;
  end;

  function TDMAttribute.isNumeric : Boolean;
  begin
    Result := m_Type = ATTRIBUTE_TYPE_NUMERIC;
  end;

  function TDMAttribute.isString : Boolean;
  begin
    Result := m_Type = ATTRIBUTE_TYPE_STRING;
  end;

  function TDMAttribute.getLowerNumericBound : Double;
  begin
    Result := m_LowerBound;
  end;

  function TDMAttribute.getUpperBumericBound : Double;
  begin
    Result := m_UpperBound;
  end;

  function TDMAttribute.lowerNumericBoundIsOpen : Boolean;
  begin
    Result := m_LowerBoundIsOpen;
  end;

  function TDMAttribute.upperNumericBoundIsOpen : Boolean;
  begin
    Result := m_UpperBoundIsOpen;
  end;

  function TDMAttribute.numValues : Integer;
  begin
    if ( m_Type <> ATTRIBUTE_TYPE_NOMINAL ) and ( m_Type <> ATTRIBUTE_TYPE_STRING ) then Result := 0
    else
      if ( m_Values = nil ) then Result := 0
      else Result := m_Values.size;
  end;

  function TDMAttribute.addStringValue( value : AnsiString ) : Integer;
  var
    store : TDMNominalAttributeValue;
    index : Integer;
  begin
    if ( m_Type <> ATTRIBUTE_TYPE_STRING ) then Result := -1
    else
    begin
      store := TDMNominalAttributeValue.Create( value );
      index := m_Values.indexOf( store );
      if ( index >= 0 ) then
      begin
        store.Destroy;
        Result := index;
      end
      else
      begin
        m_Values.addElement( store );
        Result := m_Values.size - 1;
      end;
    end;
  end;

  function TDMAttribute.addStringValue( attribute : TDMAttribute; const index : Integer ) : Integer;
  var
    navobject : TDMNominalAttributeValue;
  begin
    Result := -1;
    if ( m_Type = ATTRIBUTE_TYPE_STRING ) and ( attribute <> nil ) then
    begin
      navobject := attribute.m_Values.elementAt( index ) as TDMNominalAttributeValue;
      Result := addStringValue( navobject.m_Name );
    end;
  end;

  function TDMAttribute.enumerateValues : TDMNominalAttributeValueEnumeration;
  begin
    Result := TDMNominalAttributeValueEnumeration.Create( Self );
  end;

  function TDMAttribute.indexOfValue( value : AnsiString ) : Integer;
  var
    store : TDMNominalAttributeValue;
  begin
    if ( m_Type <> ATTRIBUTE_TYPE_NOMINAL ) and ( m_Type <> ATTRIBUTE_TYPE_STRING ) then
      Result := -1
    else
    begin
      if ( m_Values = nil ) then Result := -1
      else
      begin
        store := TDMNominalAttributeValue.Create( value );
        Result := m_Values.indexOf( store );
        store.Destroy;
      end;
    end;
  end;

  procedure TDMAttribute.delete( const valIndex : Integer );
  begin
    if ( m_Type <> ATTRIBUTE_TYPE_NOMINAL ) and ( m_Type <> ATTRIBUTE_TYPE_STRING ) then
    begin
      if ( m_Values <> nil ) then m_Values.removeElementAt( valIndex );
    end;
  end;

  procedure TDMAttribute.setIndex( const index : Integer );
  begin
    m_Index := index;
  end;

  procedure TDMAttribute.setName( name : AnsiString );
  begin
    m_Name := name;
  end;

  procedure TDMAttribute.setAttributeType( const attributeType : Integer );
  begin
    m_Type := attributeType;
  end;

  procedure TDMAttribute.setWeight( const weight : Double );
  begin
    m_Weight := weight;
  end;

  procedure TDMAttribute.setOrdering( const ordering : Integer );
  begin
    m_Ordering := ordering;
  end;

  procedure TDMAttribute.setUpperNumericBound( const upperBound : Double );
  begin
    m_UpperBound := upperBound;
  end;

  procedure TDMAttribute.setLowerNumericBound( const lowerBound : Double );
  begin
    m_LowerBound := lowerBound;
  end;

  procedure TDMAttribute.setValue( const valIndex : Integer; value : AnsiString );
  var
    valueAtIndex : TDMNominalAttributeValue;
  begin
    if ( m_Type <> ATTRIBUTE_TYPE_NOMINAL ) and ( m_Type <> ATTRIBUTE_TYPE_STRING ) then
    begin
      if ( m_Values <> nil ) then
      begin
        valueAtIndex := m_Values.elementAt( valIndex ) as TDMNominalAttributeValue;
        valueAtIndex.m_Name := value;
      end;
    end;
  end;

  function TDMAttribute.equals( otherObject : TObject ) : Boolean;
  var
    otherAttribute : TDMAttribute;
    basicFieldsOk, valuesCantCompare, valuesOk : Boolean;
  begin
    Result := false;
    if ( otherObject <> nil ) then
      if ( otherObject is TDMAttribute ) then
      begin
        otherAttribute := otherObject as TDMAttribute;
        basicFieldsOk :=
          ( otherAttribute.m_Name = m_Name) and
          ( otherAttribute.m_Type = m_Type ) and
          ( otherAttribute.m_Index = m_Index ) and
          ( otherAttribute.m_Ordering = m_Ordering ) and
          ( otherAttribute.m_Weight = m_Weight ) and
          ( otherAttribute.m_LowerBound = m_LowerBound ) and
          ( otherAttribute.m_UpperBound = m_UpperBound ) and
          ( otherAttribute.m_LowerBoundIsOpen = m_LowerBoundIsOpen ) and
          ( otherAttribute.m_UpperBoundIsOpen = m_UpperBoundIsOpen ) and
          ( otherAttribute.m_IsRegular = m_IsRegular ) and
          ( otherAttribute.m_IsAveragable = m_IsAveragable ) and
          ( otherAttribute.m_HasZeroPoint = m_HasZeroPoint );

          if ( otherAttribute.m_Type = ATTRIBUTE_TYPE_NOMINAL ) and
             ( otherAttribute.m_Type = ATTRIBUTE_TYPE_STRING ) then
          begin
            valuesCantCompare := ( otherAttribute.m_Values = nil ) xor
                                 ( m_Values = nil );

            if ( valuesCantCompare ) then valuesOk := false
            else
            begin
              if ( otherAttribute.m_Values = nil ) then valuesOk := true
              else valuesOk := m_Values.equals( otherAttribute.m_Values );
            end;
          end
          else valuesOk := true;

          Result := valuesOk and basicFieldsOk;
      end;
  end;

  function TDMAttribute.ordering : Integer;
  begin
    Result := m_Ordering;
  end;

  function TDMAttribute.isInRange( const value : Double ) : Boolean;
  var
    nominalValue : Integer;
    lowerBoundOk, upperBoundOk : Boolean;
  begin
    Result := true;
    if ( m_Type = ATTRIBUTE_TYPE_DATE ) or ( value = MISSING_VALUE ) then Result := true;
    if ( m_Type <> ATTRIBUTE_TYPE_NUMERIC ) then
    begin
      nominalValue := Round( value );
      if ( nominalValue < 0 ) or ( nominalValue >= m_Values.size )
      then Result := false;
    end
    else
    begin
      if ( m_LowerBoundIsOpen ) then lowerBoundOk := value >= m_LowerBound
      else lowerBoundOk := value > m_LowerBound;
      if ( m_UpperBoundIsOpen ) then upperBoundOk := value <= m_UpperBound
      else upperBoundOk := value < m_LowerBound;
      Result := lowerBoundOk and upperBoundOk;
    end;
  end;

  function TDMAttribute.cloneObject : TObject;
  var
    rattribute : TDMAttribute;
  begin
    if ( m_Type = ATTRIBUTE_TYPE_NOMINAL ) or ( m_Type = ATTRIBUTE_TYPE_STRING ) then
      rattribute := TDMAttribute.Create( m_Name, m_Values )
    else
    begin
      rattribute := TDMAttribute.Create( m_Name );
      rattribute.m_Values := nil;
    end;

    rattribute.m_Type := m_Type;
    rattribute.m_Index := m_Index;
    rattribute.m_Ordering := m_Ordering;
    rattribute.m_Weight := m_Weight;
    rattribute.m_LowerBound := m_LowerBound;
    rattribute.m_UpperBound := m_UpperBound;
    rattribute.m_IsRegular := m_IsRegular;
    rattribute.m_IsAveragable := m_IsAveragable;
    rattribute.m_HasZeroPoint := m_HasZeroPoint;
    rattribute.m_LowerBoundIsOpen := m_lowerBoundIsOpen;
    rattribute.m_UpperBoundIsOpen := m_upperBoundIsOpen;

    Result := rattribute as TObject;
  end;

  function TDMAttribute.copyObject : TObject;
  var
    rattribute : TDMAttribute;
    rvalues : TDMFastVector;
  begin
    if ( m_Type = ATTRIBUTE_TYPE_NOMINAL ) or ( m_Type = ATTRIBUTE_TYPE_STRING ) then
    begin
      rvalues := m_Values.copyObject as TDMFastVector;
      rattribute := TDMAttribute.Create( m_Name, rvalues );
    end
    else
    begin
      rattribute := TDMAttribute.Create( m_Name );
      rattribute.m_Values := nil;
    end;

    rattribute.m_Type := m_Type;
    rattribute.m_Index := m_Index;
    rattribute.m_Ordering := m_Ordering;
    rattribute.m_Weight := m_Weight;
    rattribute.m_LowerBound := m_LowerBound;
    rattribute.m_UpperBound := m_UpperBound;
    rattribute.m_IsRegular := m_IsRegular;
    rattribute.m_IsAveragable := m_IsAveragable;
    rattribute.m_HasZeroPoint := m_HasZeroPoint;
    rattribute.m_LowerBoundIsOpen := m_lowerBoundIsOpen;
    rattribute.m_UpperBoundIsOpen := m_upperBoundIsOpen;

    Result := rattribute as TObject;
  end;

  procedure TDMAttribute.serializeObject( ostream : TStream );
  begin
  end;

  procedure TDMAttribute.deserializeObject( istream : TStream );
  begin
  end;

  function TDMAttribute.toString : AnsiString;
  var
    enu : TDMNominalAttributeValueEnumeration;
    currentValue : TDMNominalAttributeValue;
  begin
    Result := ARFF_ATTRIBUTE + ' ' + Utils.simpleQuote( m_Name ) + ' ';

    case m_Type of
      ATTRIBUTE_TYPE_NOMINAL :
      begin
        Result := Result + '{ ';
        enu := enumerateValues;
        while ( enu.hasMoreElements ) do
        begin
          currentValue := enu.nextElement;
          Result := Result + currentValue.toString;
          if ( enu.hasMoreElements ) then Result := Result + ', ';
        end;
        Result := Result + ' }';
      end;
      ATTRIBUTE_TYPE_NUMERIC :
        Result := Result + ARFF_ATTRIBUTE_NUMERIC;
      ATTRIBUTE_TYPE_STRING :
        Result := Result + ARFF_ATTRIBUTE_STRING;
      else
        Result := Result + 'unknown';
    end;
  end;

  function TDMAttribute.value( const valIndex : Integer ) : AnsiString;
  var
    valueAtIndex : TDMNominalAttributeValue;
  begin
    if ( m_Type <> ATTRIBUTE_TYPE_NOMINAL ) and ( m_Type <> ATTRIBUTE_TYPE_STRING ) then
      Result := ''
    else
    begin
      if ( m_Values <> nil ) then
      begin
        valueAtIndex := m_Values.elementAt( valIndex ) as TDMNominalAttributeValue;
        Result := valueAtIndex.m_Name;
      end
      else Result := '';
    end;
  end;

  destructor TDMAttribute.Destroy();
  begin
    FreeAndNil(m_Values);
  end;

  constructor TDMNominalAttributeValue.Create( name : AnsiString );
  begin
    m_Name := name;
  end;

  function TDMNominalAttributeValue.cloneObject : TObject;
  begin
    Result := TDMNominalAttributeValue.Create( m_Name );
  end;

  function TDMNominalAttributeValue.copyObject : TObject;
  begin
    Result := TDMNominalAttributeValue.Create( m_Name );
  end;

  function TDMNominalAttributeValue.equals( otherObject : TObject ) : Boolean;
  var
    navobject : TDMNominalAttributeValue;
  begin
    if ( otherObject = nil ) then Result := false
    else
      if ( otherObject is TDMNominalAttributeValue ) then
      begin
        navobject := otherObject as TDMNominalAttributeValue;
        Result := navobject.m_Name = m_Name;
      end
      else Result := false;
  end;

  function TDMNominalAttributeValue.toString : AnsiString;
  begin
    Result := Utils.simpleQuote( m_Name );
  end;

  procedure TDMNominalAttributeValue.serializeObject( ostream : TStream );
  var
    slength : Integer;
  begin
    if ( ostream <> nil ) then
    begin
      slength := Length( m_Name );
      ostream.Write( slength, 4 );
      ostream.WriteBuffer( PChar( m_Name )^, slength );
    end;
  end;

  procedure TDMNominalAttributeValue.deserializeObject( istream : TStream );
  var
    slength : Integer;
  begin
    if ( istream <> nil ) then
    begin
      istream.Read( slength, 4 );
      if ( slength > 0 ) then
      begin
        SetLength( m_Name, slength );
        istream.Read( PChar( m_Name )^, slength )
      end;
    end;
  end;

  constructor TDMNominalAttributeValueEnumeration.Create( attribute : TDMAttribute );
  begin
    if ( attribute.isNominal ) then
    begin
      m_Counter := 0;
      m_FastVector := attribute.m_Values;
      m_SpecialElement := -1;
    end;
  end;

  function TDMNominalAttributeValueEnumeration.hasMoreElements : Boolean;
  begin
    Result := false;
    if ( m_Counter < m_FastVector.size ) then Result := true;
  end;

  function TDMNominalAttributeValueEnumeration.nextElement : TDMNominalAttributeValue;
  begin
    Result := m_FastVector.elementAt( m_Counter ) as TDMNominalAttributeValue;
    m_Counter := m_Counter + 1;
    if ( m_Counter = m_SpecialElement ) then m_Counter := m_Counter + 1;
  end;

end.
Соседние файлы в папке DMCore