module Problems

! Parameters that define the types of the possible bound constraints on
! a variable.
  integer, parameter :: EQUAL         = 0
  integer, parameter :: GREATER_EQUAL = 1
  integer, parameter :: LESS_EQUAL    = 2

! These parameters are used to distinguish various kinds of
! variables. One variable can be CONTINUOUS (which is assumed for each
! variable, unless the contrary is specified), BINARY (a 0-1 variable),
! DISCRETE (variables that takes values in a discrete set) and INTEGER.
  integer, parameter :: BINARY   = 3
  integer, parameter :: DISCRETE = 4
  integer, parameter :: INTEGER  = 5

! ************************************************************************
! ************************************************************************

  type domain

!    This structure represents constraints on the variables of a
!    problem. The 'indices' array stores the indices of the variables
!    related to the constraints. The 'type' array can stores (i) the
!    type of the i-th constraint, which can be either an equality
!    (EQUAL) or an inequality one (that is divided in two types: "less
!    than or equal to" (LESS_EQUAL) and "greater than or equal to"
!    (GREATER_EQUAL)), or (ii) the type of the variable (BINARY,
!    DISCRETE or INTEGER).

!    The indices of the variables.
     integer, pointer :: indices(:)

!    TYPE(i) indicates the bound type (EQUAL, LESS_EQUAL, GREATE_EQUAL) on
!    the variable or the kind (BINARY, DISCRETE or INTEGER) of the variable
!    whose index is INDICES(i).
     integer, pointer :: type(:)

!    In the case the constraint represents a bound on the variable,
!    VALUE(i) indicates the maximum ("LESS_EQUAL bound"), minimum
!    ("GREATER_EQUAL bound") or the exact ("EQUAL bound") value
!    of the variable.
     real(kind=8), pointer :: value(:)

  end type domain

! ************************************************************************
! ************************************************************************

  type problem

!    This structure represents a problem. It stores the domain of the
!    variables and the initial point of the problem.

     integer               :: id, fatherId
     real(kind=8)          :: lowerBound
     type(domain)          :: domain
     real(kind=8), pointer :: initialPoint(:)

     integer :: geninfo,geninfoFather

     ! Index and value of the branching variable that was responsible
     ! to create this subproblem.
     integer      :: indexBranchingVariable
     real(kind=8) :: branchingVariableValue
     logical      :: downBranch

     real(kind=8) :: estimation,solutionValue

     integer :: depth
     logical :: solved

  end type problem

! ************************************************************************
! ************************************************************************

contains
  
  function createProblem(n,x,c,id,fatherId,lowerBound,indexBranchingVariable, &
       branchingVariableValue,downBranch,depth) result (p)

    use Constants

    implicit none

!   This function creates a problem that can have up to m constraints
!   and n variables.
!
!   Parameters of the function:
!   ===========================
!
!   N integer: Number of variables.
!   ---------
!
!   Returns:
!   ========
!
!   P problem: The problem created.
!   ---------

!   SCALAR ARGUMENTS
    integer,      intent(in) :: n, id, fatherId, indexBranchingVariable
    real(kind=8), intent(in) :: branchingVariableValue
    logical,      intent(in) :: downBranch
    integer,      intent(in) :: depth

!   OTHER ARGUMENTS
    real(kind=8), intent(in) :: x(n)
    real(kind=8), intent(in) :: lowerBound
    type(domain), intent(in) :: c

!   RETURN VARIABLE
    type(problem) :: p

    allocate(p%initialPoint(n))

    p%id = id
    p%fatherId   = fatherId
    p%lowerBound = lowerBound

    p%initialPoint = x
    
    p%domain%indices => c%indices
    p%domain%type    => c%type
    p%domain%value   => c%value

    p%indexBranchingVariable = indexBranchingVariable
    p%branchingVariableValue = branchingVariableValue
    p%downBranch = downBranch

    p%estimation = 0.0d0

    p%solutionValue = LARGEST_VALUE

    p%depth = depth

    p%solved = .false.

  end function createProblem

! ************************************************************************
! ************************************************************************

  subroutine deallocateProblem(p)

    type(problem), intent(in out) :: p

    call deallocateDomain(p%domain)
    deallocate(p%initialPoint)

  end subroutine deallocateProblem

! ************************************************************************
! ************************************************************************

  function createDomain(m, indices, type, value) result (domain_)

    implicit none

!   SCALAR ARGUMENTS
    integer, intent(in) :: m

!   ARRAY ARGUMENTS
    integer,      intent(in) :: indices(m), type(m)
    real(kind=8), intent(in) :: value(m)

!   This function creates a structure that can have up to m constraints.
!
!   Parameters of the function:
!   ===========================
!
!   M integer: Maximum number of constraints.
!   ---------
!
!   INDICES integer indices(m): Indices of the variables.
!   --------------------------
!
!   TYPE integer type(m): Types of each constraint.
!   --------------------
!
!   VALUE real(kind=8) value(m): Values of each constraint.
!   ---------------------------
!
!   Returns:
!   ========
!
!   DOMAIN_ domain: The domain created.
!   --------------

!   RETURN VARIABLE
    type(domain) :: domain_

    allocate(domain_%indices(m))
    allocate(domain_%type(m))
    allocate(domain_%value(m))

    domain_%indices = indices
    domain_%type    = type
    domain_%value   = value

  end function createDomain

! ************************************************************************
! ************************************************************************

  subroutine deallocateDomain(domain_)

    type(domain) :: domain_

    deallocate(domain_%indices)
    deallocate(domain_%type)
    deallocate(domain_%value)

  end subroutine deallocateDomain

end module Problems
