-- |
-- Module      : Data.Rhythm.Partitions
-- Copyright   : (c) Eric Bailey, 2024-2025
--
-- License     : MIT
-- Maintainer  : eric@ericb.me
-- Stability   : experimental
-- Portability : POSIX
--
-- [Integer partitions](https://mathworld.wolfram.com/Partition.html), i.e.,
-- representations of integers as a sum of positive integers where the order of
-- the summands is not significant.
module Data.Rhythm.Partitions
  ( partitions,
    partitionsAllowed,
    partitionsLength,
    partitionsLengthAllowed,
  )
where

import Math.Combinat.Partitions (Partition, fromPartition, partitionsWithKParts)
import Math.Combinat.Partitions qualified as Partitions

-- | Partitions of a given number.
--
-- >>> partitions 3
-- [Partition [1,1,1],Partition [2,1],Partition [3]]
partitions :: Int -> [Partition]
partitions :: Int -> [Partition]
partitions = Int -> [Partition]
Partitions.partitions

-- | Partitions with allowed parts.
--
-- >>> partitionsAllowed [1,2,3] 4
-- [Partition [1,1,1,1],Partition [2,1,1],Partition [2,2],Partition [3,1]]
partitionsAllowed :: (Foldable t) => t Int -> Int -> [Partition]
partitionsAllowed :: forall (t :: * -> *). Foldable t => t Int -> Int -> [Partition]
partitionsAllowed t Int
allowed Int
n =
  (Partition -> Bool) -> [Partition] -> [Partition]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> t Int -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` t Int
allowed) ([Int] -> Bool) -> (Partition -> [Int]) -> Partition -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Partition -> [Int]
fromPartition) (Int -> [Partition]
partitions Int
n)

-- | Partitions of a given length.
--
-- >>> partitionsLength 3 7
-- [Partition [3,2,2],Partition [3,3,1],Partition [4,2,1],Partition [5,1,1]]
partitionsLength :: Int -> Int -> [Partition]
partitionsLength :: Int -> Int -> [Partition]
partitionsLength = Int -> Int -> [Partition]
partitionsWithKParts

-- | Partitions of a given length with allowed parts.
--
-- >>> partitionsLengthAllowed 2 [1,2,3] 4
-- [Partition [2,2],Partition [3,1]]
partitionsLengthAllowed :: (Foldable t) => Int -> t Int -> Int -> [Partition]
partitionsLengthAllowed :: forall (t :: * -> *).
Foldable t =>
Int -> t Int -> Int -> [Partition]
partitionsLengthAllowed Int
len t Int
allowed =
  (Partition -> Bool) -> [Partition] -> [Partition]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> t Int -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` t Int
allowed) ([Int] -> Bool) -> (Partition -> [Int]) -> Partition -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Partition -> [Int]
fromPartition) ([Partition] -> [Partition])
-> (Int -> [Partition]) -> Int -> [Partition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> [Partition]
partitionsLength Int
len