MODULE  INTEGER_SETS
!  This  module  is  intended  to  illustrate  use  of  the  module  facility
!  to  define  a  new  data  type,  along  with  suitable  operators.

INTEGER,  PARAMETER  ::  MAX_SET_CARD  =  200

TYPE  SET  !  Define  SET  data  type
  PRIVATE
  INTEGER  CARD
  INTEGER  ELEMENT  (MAX_SET_CARD)
END  TYPE  SET

INTERFACE  OPERATOR  (.IN.)
  MODULE  PROCEDURE  ELEMENT
END  INTERFACE

INTERFACE  OPERATOR  (<=)
  MODULE  PROCEDURE  SUBSET
END  INTERFACE

INTERFACE  OPERATOR  (+)
  MODULE  PROCEDURE  UNION
END  INTERFACE

INTERFACE  OPERATOR  (-)
  MODULE  PROCEDURE  DIFFERENCE
END  INTERFACE

INTERFACE  OPERATOR  (*)
  MODULE  PROCEDURE  INTERSECTION
END  INTERFACE

CONTAINS

INTEGER  FUNCTION  CARDINALITY  (A)  !  Returns  cardinality  of  set  A
  TYPE  (SET)  A
  CARDINALITY  =  A  %  CARD
END  FUNCTION  CARDINALITY

LOGICAL  FUNCTION  ELEMENT  (X,  A)  !  Determines  if
  INTEGER  X  !  element  X  is  in  set  A
  TYPE  (SET)  A
  INTENT (IN) X, A
  ELEMENT  =  ANY  (A  %  ELEMENT  (1  :  A  %  CARD)  .EQ.  X)
END  FUNCTION  ELEMENT

FUNCTION  UNION  (A,  B)  !  Union  of  sets  A  and  B
  TYPE  (SET)  A,  B,  UNION
  INTENT (IN) A, B
  INTEGER  J
  UNION  =  A
  DO  J  =  1,  B  %  CARD
  IF  (.NOT.  (B  %  ELEMENT  (J)  .IN.  A))  THEN
  IF  (UNION  %  CARD  <  MAX_SET_CARD)  THEN
  UNION  %  CARD  =  UNION  %  CARD  +  1
  UNION  %  ELEMENT  (UNION  %  CARD)  =  &
  B  %  ELEMENT  (J)
  ELSE
  !  Maximum  set  size  exceeded  .  .  .
  END  IF
  END  IF
  END  DO
END  FUNCTION  UNION

FUNCTION  DIFFERENCE  (A,  B)  !  Difference  of  sets  A  and  B
  TYPE  (SET)  A,  B,  DIFFERENCE
  INTENT (IN) A, B
  INTEGER  J,  X
  DIFFERENCE  %  CARD  =  0  !  The  empty  set
  DO  J  =  1,  A  %  CARD
  X  =  A  %  ELEMENT  (J)
  IF  (.NOT.  (X  .IN.  B))  DIFFERENCE  =  DIFFERENCE  +  SET  (1,  X)
  END  DO
END  FUNCTION  DIFFERENCE

FUNCTION  INTERSECTION  (A,  B)  !  Intersection  of  sets  A  and  B
  TYPE  (SET)  A,  B,  INTERSECTION
  INTENT (IN) A, B
  INTERSECTION  =  A  -  (A  -  B)
END  FUNCTION  INTERSECTION

LOGICAL  FUNCTION  SUBSET  (A,  B)  !  Determines  if  set  A  is
  TYPE  (SET)  A,  B  !  a  subset  of  set  B
  INTENT (IN) A, B
  INTEGER  I
  SUBSET  =  A  %  CARD  <=  B  %  CARD
  IF  (.NOT.  SUBSET)  RETURN  !  For  efficiency
  DO  I  =  1,  A  %  CARD
  SUBSET  =  SUBSET  .AND.  (A  %  ELEMENT  (I)  .IN.  B)
  END  DO
END  FUNCTION  SUBSET

TYPE  (SET)  FUNCTION  SETF  (V)  !  Transfer  function  between  a  vector
  INTEGER  V  (:)  !  of  elements  and  a  set  of  elements
  INTEGER  J  !  removing  duplicate  elements
  SETF  %  CARD  =  0
  DO  J  =  1,  SIZE  (V)
  IF  (.NOT.  (V  (J)  .IN.  SETF))  THEN
  IF  (SETF  %  CARD  <  MAX_SET_CARD)  THEN
  SETF  %  CARD  =  SETF  %  CARD  +  1
  SETF  %  ELEMENT  (SETF  %  CARD)  =  V  (J)
  ELSE
  !  Maximum  set  size  exceeded  .  .  .
  END  IF
  END  IF
  END  DO
END  FUNCTION  SETF

FUNCTION  VECTOR  (A)  !  Transfer  the  values  of  set  A
  TYPE  (SET)  A  !  into  a  vector  in  ascending  order
  INTEGER,  POINTER  ::  VECTOR  (:)
  INTEGER  I,  J,  K
  ALLOCATE  (VECTOR  (A  %  CARD))
  VECTOR  =  A  %  ELEMENT  (1  :  A  %  CARD)
  DO  I  =  1,  A  %  CARD  -  1  !  Use  a  better  sort  if
  DO  J  =  I  +  1,  A  %  CARD  !  A  %  CARD  is  large
  IF  (VECTOR  (I)  >  VECTOR  (J))  THEN
  K  =  VECTOR  (J);  VECTOR  (J)  =  VECTOR  (I);  VECTOR  (I)  =  K
  END  IF
  END  DO
  END  DO
END  FUNCTION  VECTOR

END  MODULE  INTEGER_SETS
