! !//////////////////////////////////////////////////////////////////////// ! ! SparseMatrixClass.f90 ! Created: July 29, 2013 10:59 AM ! By: David Kopriva ! ! !//////////////////////////////////////////////////////////////////////// ! !>FTSparseMatrixData is used by the FTSparseMatrix Class. Users will !>usually not interact with or use this class directly. !> Module FTSparseMatrixData USE FTObjectClass IMPLICIT NONE ! ! --------------- ! Type definition ! --------------- ! TYPE, EXTENDS(FTObject) :: MatrixData INTEGER :: key CLASS(FTObject), POINTER :: object ! ! ======== CONTAINS ! ======== ! PROCEDURE :: initWithObjectAndKey PROCEDURE :: destruct => destructMatrixData END TYPE MatrixData INTERFACE cast MODULE PROCEDURE castObjectToMatrixData END INTERFACE cast ! ! ======== CONTAINS ! ======== ! ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE initWithObjectAndKey(self,object,key) ! ! ---------------------- ! Designated initializer ! ---------------------- ! IMPLICIT NONE CLASS(MatrixData) :: self CLASS(FTObject), POINTER :: object INTEGER :: key CALL self % FTObject % init() self % key = key self % object => object CALL self % object % retain() END SUBROUTINE initWithObjectAndKey ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE destructMatrixData(self) IMPLICIT NONE CLASS(MatrixData) :: self IF ( ASSOCIATED(self % object) ) THEN CALL releaseFTObject(self = self % object) END IF CALL self % FTObject % destruct END SUBROUTINE destructMatrixData ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE castObjectToMatrixData(obj,cast) IMPLICIT NONE ! ! ----------------------------------------------------- ! Cast the base class FTObject to the FTException class ! ----------------------------------------------------- ! CLASS(FTObject) , POINTER :: obj CLASS(MatrixData), POINTER :: cast cast => NULL() SELECT TYPE (e => obj) TYPE is (MatrixData) cast => e CLASS DEFAULT END SELECT END SUBROUTINE castObjectToMatrixData ! !//////////////////////////////////////////////////////////////////////// ! FUNCTION matrixDataCast(obj) RESULT(cast) IMPLICIT NONE ! ! ----------------------------------------------------- ! Cast the base class FTObject to the FTException class ! ----------------------------------------------------- ! CLASS(FTObject) , POINTER :: obj CLASS(MatrixData), POINTER :: cast cast => NULL() SELECT TYPE (e => obj) TYPE is (MatrixData) cast => e CLASS DEFAULT END SELECT END FUNCTION matrixDataCast END Module FTSparseMatrixData !@mark - !>The sparse matrix stores an FTObject pointer associated !>with two keys (i,j) as a hash table. !> !>Hash tables are data structures designed to enable storage and fast !>retrieval of key-value pairs. An example of a key-value pair is !>a variable name (``gamma'') and its associated value (``1.4''). !>The table itself is typically an array. !>The location of the value in a hash table associated with !>a key, $k$, is specified by way of a hash function, $H(k)$. !>In the case of a variable name and value, the hash function !>would convert the name into an integer that tells where to !>find the associated value in the table. !> !>A very simple example of a !>hash table is, in fact, a singly dimensioned array. The key is !>the array index and the value is what is stored at that index. !>Multiple keys can be used to identify data; a two dimensional !>array provides an example of where two keys are used to access memory !>and retrieve the value at that location. !>If we view a singly dimensioned array as a special case of a hash table, !>its hash function is just the array index, $H(j)=j$. A doubly dimensioned array !>could be (and often is) stored columnwise as a singly dimensioned array by creating a hash !>function that maps the two indices to a single location in the array, e.g., !>$H(i,j) = i + j*N$, where $N$ is the range of the first index, $i$. !> !>Two classes are included in FTObjectLibrary. The first, FTSparseMatrix, works with an ordered pair, (i,j), as the !>keys. The second, FTMultiIndexTable, uses an array of integers as the keys. !> !>Both classes include enquiry functions to see of an object exists for the given keys. Otherwise, !>the function that returns an object for a given key will return an UNASSOCIATED pointer if there !>is no object for the key. Be sure to retain any object returned by the objectForKeys methods if !>you want to keep it beyond the lifespan of the matrix or table. For example, !> !> TYPE(FTObject) :: obj !> obj => matrix % objectForKeys(i,j) !> IF ( ASSOCIATED(OBJ) ) THEN !> CALL obj % retain() !> Cast obj to something useful !> ELSE !> Perform some kind of error recovery !> END IF !>The sparse matrix stores an FTObject pointer associated !>with two keys (i,j) as a hash table. The size, N = the range of i. !> !>##Definition (Subclass of FTObject) !> !> TYPE(FTSparseMatrix) :: SparseMatrix !>#Usage !>##Initialization !> !> CALL SparseMatrix % initWithSize(N) !> !>##Destruction !> !> CALL release(SparseMatrix) !> !>##Adding an object !> !> CLASS(FTObject), POINTER :: obj !> CALL SparseMatrix % addObjectForKeys(obj,i,j) !> !>##Retrieving an object !> !> CLASS(FTObject), POINTER :: obj !> obj => SparseMatrix % objectForKeys(i,j) !> !>Be sure to retain the object if you want it to live !> beyond the life of the table. !> !>##Testing the presence of keys !> !> LOGICAL :: exists !> exists = SparseMatrix % containsKeys(i,j) ! !//////////////////////////////////////////////////////////////////////// ! Module FTSparseMatrixClass USE FTObjectClass USE FTLinkedListClass USE FTLinkedListIteratorClass USE FTSparseMatrixData IMPLICIT NONE ! ! ---------------------- ! Class type definitions ! ---------------------- ! TYPE FTLinkedListPtr CLASS(FTLinkedList), POINTER :: list END TYPE FTLinkedListPtr PRIVATE :: FTLinkedListPtr TYPE, EXTENDS(FTObject) :: FTSparseMatrix TYPE(FTLinkedListPtr) , DIMENSION(:), ALLOCATABLE :: table TYPE(FTLinkedListIterator), PRIVATE :: iterator ! ! ======== CONTAINS ! ======== ! PROCEDURE :: initWithSize => initSparseMatrixWithSize PROCEDURE :: destruct => destructSparseMatrix PROCEDURE :: containsKeys => SparseMatrixContainsKeys PROCEDURE :: addObjectForKeys => addObjectToSparseMatrixForKeys PROCEDURE :: objectForKeys => objectInSparseMatrixForKeys PROCEDURE :: SparseMatrixSize END TYPE FTSparseMatrix INTERFACE release MODULE PROCEDURE releaseFTSparseMatrix END INTERFACE ! ! ======== CONTAINS ! ======== ! ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE initSparseMatrixWithSize(self,N) IMPLICIT NONE ! ! --------- ! Arguments ! --------- ! CLASS(FTSparseMatrix) :: self INTEGER :: N ! ! --------------- ! Local variables ! --------------- ! INTEGER :: j CALL self % FTObject % init() ALLOCATE(self % table(N)) DO j = 1, N ALLOCATE(self % table(j) % list) CALL self % table(j) % list % init() END DO CALL self % iterator % init() END SUBROUTINE initSparseMatrixWithSize ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE addObjectToSparseMatrixForKeys(self,obj,i,j) IMPLICIT NONE ! ! --------- ! Arguments ! --------- ! CLASS(FTSparseMatrix) :: self CLASS(FTObject), POINTER :: obj ! ! --------------- ! Local variables ! --------------- ! CLASS(MatrixData), POINTER :: mData CLASS(FTObject) , POINTER :: ptr INTEGER :: i,j IF ( .NOT.self % containsKeys(i,j) ) THEN ALLOCATE(mData) CALL mData % initWithObjectAndKey(obj,j) ptr => mData CALL self % table(i) % list % add(ptr) CALL releaseFTObject(ptr) END IF END SUBROUTINE addObjectToSparseMatrixForKeys ! !//////////////////////////////////////////////////////////////////////// ! FUNCTION objectInSparseMatrixForKeys(self,i,j) RESULT(r) ! ! --------------------------------------------------------------- ! Returns the stored FTObject for the keys (i,j). Returns NULL() ! if the object isn't in the table. Retain the object if it needs ! a strong reference by the caller. ! --------------------------------------------------------------- ! IMPLICIT NONE ! ! --------- ! Arguments ! --------- ! CLASS(FTSparseMatrix) :: self INTEGER :: i,j CLASS(FTObject), POINTER :: r ! ! --------------- ! Local variables ! --------------- ! CLASS(MatrixData) , POINTER :: mData CLASS(FTObject) , POINTER :: obj CLASS(FTLinkedList), POINTER :: list r => NULL() IF(.NOT.ALLOCATED(self % table)) RETURN list => self % table(i) % list IF(.NOT.ASSOCIATED(list)) RETURN IF ( list % COUNT() == 0 ) RETURN ! ! ---------------------------- ! Step through the linked list ! ---------------------------- ! r => NULL() CALL self % iterator % setLinkedList(self % table(i) % list) DO WHILE (.NOT.self % iterator % isAtEnd()) obj => self % iterator % object() CALL cast(obj,mData) IF ( mData % key == j ) THEN r => mData % object EXIT END IF CALL self % iterator % moveToNext() END DO END FUNCTION objectInSparseMatrixForKeys ! !//////////////////////////////////////////////////////////////////////// ! FUNCTION SparseMatrixContainsKeys(self,i,j) RESULT(r) IMPLICIT NONE ! ! --------- ! Arguments ! --------- ! CLASS(FTSparseMatrix) :: self INTEGER :: i, j LOGICAL :: r ! ! --------------- ! Local variables ! --------------- ! CLASS(FTObject) , POINTER :: obj CLASS(MatrixData) , POINTER :: mData CLASS(FTLinkedList), POINTER :: list r = .FALSE. IF(.NOT.ALLOCATED(self % table)) RETURN IF(.NOT.ASSOCIATED(self % table(i) % list)) RETURN IF ( self % table(i) % list % COUNT() == 0 ) RETURN ! ! ---------------------------- ! Step through the linked list ! ---------------------------- ! list => self % table(i) % list CALL self % iterator % setLinkedList(list) CALL self % iterator % setToStart() DO WHILE (.NOT.self % iterator % isAtEnd()) obj => self % iterator % object() CALL cast(obj,mData) IF ( mData % key == j ) THEN r = .TRUE. RETURN END IF CALL self % iterator % moveToNext() END DO END FUNCTION SparseMatrixContainsKeys ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE destructSparseMatrix(self) IMPLICIT NONE ! ! --------- ! Arguments ! --------- ! CLASS(FTSparseMatrix) :: self ! ! --------------- ! Local variables ! --------------- ! INTEGER :: j DO j = 1, SIZE(self % table) IF ( ASSOCIATED(self % table(j) % list) ) THEN CALL releaseSMMemberList(list = self % table(j) % list) END IF END DO IF(ALLOCATED(self % table)) DEALLOCATE(self % table) CALL self % iterator % destruct() CALL self % FTObject % destruct() END SUBROUTINE destructSparseMatrix ! !------------------------------------------------ !> Public, generic name: release(self) !> !> Call release(self) on an object to release control !> of an object. If its reference count is zero, then !> it is deallocated. !------------------------------------------------ ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE releaseFTSparseMatrix(self) IMPLICIT NONE CLASS(FTSparseMatrix) , POINTER :: self CLASS(FTObject) , POINTER :: obj IF(.NOT. ASSOCIATED(self)) RETURN obj => self CALL releaseFTObject(self = obj) IF ( .NOT. ASSOCIATED(obj) ) THEN self => NULL() END IF END SUBROUTINE releaseFTSparseMatrix ! !//////////////////////////////////////////////////////////////////////// ! SUBROUTINE releaseSMMemberList(list) IMPLICIT NONE CLASS(FTLinkedList), POINTER :: list CLASS(FTObject) , POINTER :: obj obj => list CALL releaseFTObject(self = obj) IF(.NOT. ASSOCIATED(obj)) list => NULL() END SUBROUTINE releaseSMMemberList ! !//////////////////////////////////////////////////////////////////////// ! INTEGER FUNCTION SparseMatrixSize(self) IMPLICIT NONE CLASS(FTSparseMatrix) :: self IF ( ALLOCATED(self % table) ) THEN SparseMatrixSize = SIZE(self % table) ELSE SparseMatrixSize = 0 END IF END FUNCTION SparseMatrixSize ! !//////////////////////////////////////////////////////////////////////// ! FUNCTION SparseMatrixFromObject(obj) RESULT(cast) ! ! ----------------------------------------------------- ! Cast the base class FTObject to the FTException class ! ----------------------------------------------------- ! IMPLICIT NONE CLASS(FTObject) , POINTER :: obj CLASS(FTSparseMatrix), POINTER :: cast cast => NULL() SELECT TYPE (e => obj) TYPE is (FTSparseMatrix) cast => e CLASS DEFAULT END SELECT END FUNCTION SparseMatrixFromObject ! !//////////////////////////////////////////////////////////////////////// ! INTEGER FUNCTION Hash1( idPair ) INTEGER, DIMENSION(2) :: idPair Hash1 = MAXVAL(idPair) END FUNCTION Hash1 ! !//////////////////////////////////////////////////////////////////////// ! INTEGER FUNCTION Hash2( idPair ) INTEGER, DIMENSION(2) :: idPair Hash2 = MINVAL(idPair) END FUNCTION Hash2 END Module FTSparseMatrixClass