    -- Copyright 2024 United States Government as represented by the Administrator
    -- of the National Aeronautics and Space Administration. All Rights Reserved.
    --
    -- Disclaimers
    --
    -- Licensed under the Apache License, Version 2.0 (the "License"); you may
    -- not use this file except in compliance with the License. You may obtain a
    -- copy of the License at
    --
    --      https://www.apache.org/licenses/LICENSE-2.0
    --
    -- Unless required by applicable law or agreed to in writing, software
    -- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    -- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    -- License for the specific language governing permissions and limitations
    -- under the License.
    --
    -- | Diagrams.
    module Data.Diagram
        ( Diagram(..)
        , diagramStates
        , diagramNumStates
        , diagramInitialState
        , diagramFinalState
        , diagramBadState
        )
      where

    -- External imports
    import Data.List (nub, sort)

    -- | Internal representation for diagrams.
    newtype Diagram = Diagram
        { Diagram -> [(Int, String, Int)]
    diagramTransitions :: [(Int, String, Int)]
        }
      deriving (Int -> Diagram -> ShowS
    [Diagram] -> ShowS
    Diagram -> String
    (Int -> Diagram -> ShowS)
    -> (Diagram -> String) -> ([Diagram] -> ShowS) -> Show Diagram
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Diagram -> ShowS
    showsPrec :: Int -> Diagram -> ShowS
    $cshow :: Diagram -> String
    show :: Diagram -> String
    $cshowList :: [Diagram] -> ShowS
    showList :: [Diagram] -> ShowS
    Show, Diagram -> Diagram -> Bool
    (Diagram -> Diagram -> Bool)
    -> (Diagram -> Diagram -> Bool) -> Eq Diagram
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Diagram -> Diagram -> Bool
    == :: Diagram -> Diagram -> Bool
    $c/= :: Diagram -> Diagram -> Bool
    /= :: Diagram -> Diagram -> Bool
    Eq)

    -- | States in a diagram.
    diagramStates :: Diagram -> [Int]
    diagramStates :: Diagram -> [Int]
    diagramStates Diagram
    diagram = [Int] -> [Int]
    forall a. Eq a => [a] -> [a]
    nub ([Int] -> [Int]) -> [Int] -> [Int]
    forall a b. (a -> b) -> a -> b
    $ [Int] -> [Int]
    forall a. Ord a => [a] -> [a]
    sort ([Int] -> [Int]) -> [Int] -> [Int]
    forall a b. (a -> b) -> a -> b
    $ [[Int]] -> [Int]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat
      [ [Int
    s, Int
    d] | (Int
    s, String
    _, Int
    d) <- Diagram -> [(Int, String, Int)]
    diagramTransitions Diagram
    diagram ]

    -- | Number of states in a diagram.
    diagramNumStates :: Diagram -> Int
    diagramNumStates :: Diagram -> Int
    diagramNumStates = [Int] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length ([Int] -> Int) -> (Diagram -> [Int]) -> Diagram -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Diagram -> [Int]
    diagramStates

    -- | Initial state of a diagram.
    diagramInitialState :: Diagram -> Int
    diagramInitialState :: Diagram -> Int
    diagramInitialState = [Int] -> Int
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    minimum ([Int] -> Int) -> (Diagram -> [Int]) -> Diagram -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Diagram -> [Int]
    diagramStates

    -- | Final state of a diagram.
    --
    -- PRE: The diagram obtains one and only one final state.
    diagramFinalState :: Diagram -> Int
    diagramFinalState :: Diagram -> Int
    diagramFinalState = [Int] -> Int
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    maximum ([Int] -> Int) -> (Diagram -> [Int]) -> Diagram -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Diagram -> [Int]
    diagramStates

    -- | Return a state value that does not represent any state in the diagram.
    diagramBadState :: Diagram -> Int
    diagramBadState :: Diagram -> Int
    diagramBadState Diagram
    diag = [Int] -> Int
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    maximum (Diagram -> [Int]
    diagramStates Diagram
    diag) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1