module Chiasma.Ui.Measure.Balance where

import Data.List (zipWith3)
import qualified Data.List.NonEmpty as NonEmpty (
  filter,
  toList,
  zip,
  zipWith,
  )
import GHC.Float (float2Int, int2Float)
import GHC.Float.RealFracMethods (floorFloatInt)

import Chiasma.Ui.Measure.Weights (
  amendAndNormalizeWeights,
  normalizeWeights,
  )

zipWith3NE :: (a -> b -> c -> d)  ->  NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d
zipWith3NE :: (a -> b -> c -> d)
-> NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d
zipWith3NE a -> b -> c -> d
z ~(a
a :| [a]
as) ~(b
b :| [b]
bs) ~(c
c :| [c]
cs) =
  a -> b -> c -> d
z a
a b
b c
c d -> [d] -> NonEmpty d
forall a. a -> [a] -> NonEmpty a
:| (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
forall a b c d. (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
zipWith3 a -> b -> c -> d
z [a]
as [b]
bs [c]
cs

data Balance =
  Balance {
    Balance -> NonEmpty Float
balanceMin :: NonEmpty Float,
    Balance -> NonEmpty (Maybe Float)
balanceMax :: NonEmpty (Maybe Float),
    Balance -> NonEmpty Float
balanceWeights :: NonEmpty Float,
    Balance -> NonEmpty Bool
balanceMinimized :: NonEmpty Bool,
    Balance -> Float
balanceTotal :: Float
  }

reverseWeights :: NonEmpty Float -> NonEmpty Float
reverseWeights :: NonEmpty Float -> NonEmpty Float
reverseWeights NonEmpty Float
weights =
  if Float
norm Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
> Float
0 then (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
norm) NonEmpty Float
r else NonEmpty Float
r
  where
    r :: NonEmpty Float
r = (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Float
1 Float -> Float -> Float
forall a. Num a => a -> a -> a
-) NonEmpty Float
weights
    norm :: Float
norm = NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
r

cutSizes :: Balance -> NonEmpty Float
cutSizes :: Balance -> NonEmpty Float
cutSizes (Balance NonEmpty Float
min' NonEmpty (Maybe Float)
_ NonEmpty Float
weights NonEmpty Bool
_ Float
total) =
  (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Float -> Float
addDist NonEmpty Float
cut
  where
    surplus :: Float
surplus = NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
min' Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
total
    dist :: NonEmpty Float
dist = (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Float
surplus Float -> Float -> Float
forall a. Num a => a -> a -> a
*) (NonEmpty Float -> NonEmpty Float
reverseWeights NonEmpty Float
weights)
    cut :: NonEmpty Float
cut = ((Float, Float) -> Float)
-> NonEmpty (Float, Float) -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Float -> Float -> Float) -> (Float, Float) -> Float
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (-)) (NonEmpty Float -> NonEmpty Float -> NonEmpty (Float, Float)
forall a b. NonEmpty a -> NonEmpty b -> NonEmpty (a, b)
NonEmpty.zip NonEmpty Float
min' NonEmpty Float
dist)
    negOrZero :: p -> p
negOrZero p
a = if p
a p -> p -> Bool
forall a. Ord a => a -> a -> Bool
< p
0 then p
a else p
0
    neg :: NonEmpty Float
neg = (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Float -> Float
forall p. (Ord p, Num p) => p -> p
negOrZero NonEmpty Float
cut
    negTotal :: Float
negTotal = NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
neg
    negCount :: Int
negCount = [Float] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((Float -> Bool) -> NonEmpty Float -> [Float]
forall a. (a -> Bool) -> NonEmpty a -> [a]
NonEmpty.filter (Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0) NonEmpty Float
neg)
    dist2 :: Float
dist2 = Float
negTotal Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Int -> Float
int2Float (NonEmpty Float -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length NonEmpty Float
min' Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
negCount)
    addDist :: Float -> Float
addDist Float
a = if Float
a Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
0 then Float
0 else Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
dist2

distributeOnUnbounded :: Balance -> NonEmpty Float
distributeOnUnbounded :: Balance -> NonEmpty Float
distributeOnUnbounded (Balance NonEmpty Float
min' NonEmpty (Maybe Float)
max' NonEmpty Float
weights NonEmpty Bool
_ Float
total) =
  (Float -> Float -> Float)
-> NonEmpty Float -> NonEmpty Float -> NonEmpty Float
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NonEmpty.zipWith Float -> Float -> Float
addWeights NonEmpty Float
initial NonEmpty Float
newWeights
  where
    initial :: NonEmpty Float
initial = (Float -> Maybe Float -> Float)
-> NonEmpty Float -> NonEmpty (Maybe Float) -> NonEmpty Float
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NonEmpty.zipWith Float -> Maybe Float -> Float
forall a. a -> Maybe a -> a
fromMaybe NonEmpty Float
min' NonEmpty (Maybe Float)
max'
    newWeights :: NonEmpty Float
newWeights = NonEmpty Float -> NonEmpty Float
normalizeWeights (NonEmpty Float -> NonEmpty Float)
-> NonEmpty Float -> NonEmpty Float
forall a b. (a -> b) -> a -> b
$ (Float -> Maybe Float -> Float)
-> NonEmpty Float -> NonEmpty (Maybe Float) -> NonEmpty Float
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NonEmpty.zipWith Float -> Maybe Float -> Float
forall b b. Num b => b -> Maybe b -> b
weightOrZeroIfMax NonEmpty Float
weights NonEmpty (Maybe Float)
max'
    addWeights :: Float -> Float -> Float
addWeights Float
i Float
w = Float
i Float -> Float -> Float
forall a. Num a => a -> a -> a
+ (Float
w Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
surplus)
    surplus :: Float
surplus = Float
total Float -> Float -> Float
forall a. Num a => a -> a -> a
- NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
initial
    weightOrZeroIfMax :: b -> Maybe b -> b
weightOrZeroIfMax b
w = b -> (b -> b) -> Maybe b -> b
forall b a. b -> (a -> b) -> Maybe a -> b
maybe b
w (b -> b -> b
forall a b. a -> b -> a
const b
0)

weightsWithoutMinimized :: Balance -> NonEmpty Float
weightsWithoutMinimized :: Balance -> NonEmpty Float
weightsWithoutMinimized (Balance NonEmpty Float
_ NonEmpty (Maybe Float)
_ NonEmpty Float
weights NonEmpty Bool
minimized Float
_) =
  NonEmpty Float -> NonEmpty Float
normalizeWeights NonEmpty Float
zeroIfMinimizedWeights
  where
    zeroIfMinimizedWeights :: NonEmpty Float
zeroIfMinimizedWeights = (Float -> Bool -> Float)
-> NonEmpty Float -> NonEmpty Bool -> NonEmpty Float
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NonEmpty.zipWith Float -> Bool -> Float
forall p. Num p => p -> Bool -> p
zeroIfMinimized NonEmpty Float
weights NonEmpty Bool
minimized
    zeroIfMinimized :: p -> Bool -> p
zeroIfMinimized p
w Bool
m = if Bool
m then p
0 else p
w

trimWeights :: NonEmpty Bool -> NonEmpty Float -> NonEmpty Float
trimWeights :: NonEmpty Bool -> NonEmpty Float -> NonEmpty Float
trimWeights NonEmpty Bool
unsat NonEmpty Float
withoutMinimized =
  NonEmpty (Maybe Float) -> NonEmpty Float
amendAndNormalizeWeights NonEmpty (Maybe Float)
onlyUnsat
  where
    onlyUnsat :: NonEmpty (Maybe Float)
onlyUnsat = (Bool -> Float -> Maybe Float)
-> NonEmpty Bool -> NonEmpty Float -> NonEmpty (Maybe Float)
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NonEmpty.zipWith Bool -> Float -> Maybe Float
forall a. Bool -> a -> Maybe a
weightIfUnsat NonEmpty Bool
unsat NonEmpty Float
withoutMinimized
    weightIfUnsat :: Bool -> a -> Maybe a
weightIfUnsat Bool
s a
w = if Bool
s then a -> Maybe a
forall a. a -> Maybe a
Just a
w else Maybe a
forall a. Maybe a
Nothing

distRest :: Balance -> Float -> NonEmpty Float -> NonEmpty Float -> NonEmpty Float
distRest :: Balance
-> Float -> NonEmpty Float -> NonEmpty Float -> NonEmpty Float
distRest Balance
balance Float
rest NonEmpty Float
sizes NonEmpty Float
effectiveMax =
  (Float -> Float -> Float)
-> NonEmpty Float -> NonEmpty Float -> NonEmpty Float
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NonEmpty.zipWith Float -> Float -> Float
addRestWeights NonEmpty Float
sizes NonEmpty Float
restW
  where
    unsat :: NonEmpty Bool
unsat = (Float -> Float -> Bool)
-> NonEmpty Float -> NonEmpty Float -> NonEmpty Bool
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NonEmpty.zipWith Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
(>) NonEmpty Float
effectiveMax NonEmpty Float
sizes
    unsatLeft :: Bool
unsatLeft = NonEmpty Bool -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or NonEmpty Bool
unsat
    withoutMinimized :: NonEmpty Float
withoutMinimized = Balance -> NonEmpty Float
weightsWithoutMinimized Balance
balance
    restW :: NonEmpty Float
restW =
      if Bool
unsatLeft
      then NonEmpty Bool -> NonEmpty Float -> NonEmpty Float
trimWeights NonEmpty Bool
unsat NonEmpty Float
withoutMinimized
      else NonEmpty Float
withoutMinimized
    addRestWeights :: Float -> Float -> Float
addRestWeights Float
s Float
w = Float
s Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
w Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
rest

saturate :: NonEmpty Float -> NonEmpty Float -> NonEmpty Float -> Float -> NonEmpty Float
saturate :: NonEmpty Float
-> NonEmpty Float -> NonEmpty Float -> Float -> NonEmpty Float
saturate NonEmpty Float
initial NonEmpty Float
max' NonEmpty Float
initialWeights Float
total =
  NonEmpty Float -> NonEmpty Float -> NonEmpty Float
loop NonEmpty Float
initial NonEmpty Float
initialWeights
  where
    loop :: NonEmpty Float -> NonEmpty Float -> NonEmpty Float
loop NonEmpty Float
current NonEmpty Float
weights =
      if NonEmpty Float
new NonEmpty Float -> NonEmpty Float -> Bool
forall a. Eq a => a -> a -> Bool
== NonEmpty Float
current Bool -> Bool -> Bool
|| Float
rest Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Float
0 then NonEmpty Float
new else NonEmpty Float -> NonEmpty Float -> NonEmpty Float
loop NonEmpty Float
new NonEmpty Float
newWeights
      where
        rest :: Float
rest = Float
total Float -> Float -> Float
forall a. Num a => a -> a -> a
- NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
current
        unsatWeights :: NonEmpty Float
unsatWeights = (Float -> Float -> Float -> Float)
-> NonEmpty Float
-> NonEmpty Float
-> NonEmpty Float
-> NonEmpty Float
forall a b c d.
(a -> b -> c -> d)
-> NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d
zipWith3NE (\Float
s Float
m Float
w -> if Float
s Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
m then Float
0 else Float
w) NonEmpty Float
current NonEmpty Float
max' NonEmpty Float
weights
        newWeights :: NonEmpty Float
newWeights = NonEmpty Float -> NonEmpty Float
normalizeWeights NonEmpty Float
unsatWeights
        new :: NonEmpty Float
new = (Float -> Float -> Float -> Float)
-> NonEmpty Float
-> NonEmpty Float
-> NonEmpty Float
-> NonEmpty Float
forall a b c d.
(a -> b -> c -> d)
-> NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d
zipWith3NE (\Float
l Float
h Float
w -> Float -> Float -> Float
forall a. Ord a => a -> a -> a
min (Float
l Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
w Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
rest) Float
h) NonEmpty Float
current NonEmpty Float
max' NonEmpty Float
newWeights

distributeOnAll :: Balance -> NonEmpty Float
distributeOnAll :: Balance -> NonEmpty Float
distributeOnAll balance :: Balance
balance@(Balance NonEmpty Float
min' NonEmpty (Maybe Float)
max' NonEmpty Float
weights NonEmpty Bool
_ Float
total) =
  if Float
rest Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
<= Float
0 then NonEmpty Float
sizes else Balance
-> Float -> NonEmpty Float -> NonEmpty Float -> NonEmpty Float
distRest Balance
balance Float
rest NonEmpty Float
sizes NonEmpty Float
effectiveMax
  where
    effectiveMax :: NonEmpty Float
effectiveMax = Float -> Maybe Float -> Float
forall a. a -> Maybe a -> a
fromMaybe Float
1e6 (Maybe Float -> Float) -> NonEmpty (Maybe Float) -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty (Maybe Float)
max'
    sizes :: NonEmpty Float
sizes = NonEmpty Float
-> NonEmpty Float -> NonEmpty Float -> Float -> NonEmpty Float
saturate NonEmpty Float
min' NonEmpty Float
effectiveMax NonEmpty Float
weights Float
total
    rest :: Float
rest = Float
total Float -> Float -> Float
forall a. Num a => a -> a -> a
- NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
sizes

hasUnbounded :: Balance -> Bool
hasUnbounded :: Balance -> Bool
hasUnbounded =
  (Maybe Float -> Bool) -> NonEmpty (Maybe Float) -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Maybe Float -> Bool
forall a. Maybe a -> Bool
isNothing (NonEmpty (Maybe Float) -> Bool)
-> (Balance -> NonEmpty (Maybe Float)) -> Balance -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Balance -> NonEmpty (Maybe Float)
balanceMax

distributeSizes :: Balance -> NonEmpty Float
distributeSizes :: Balance -> NonEmpty Float
distributeSizes Balance
balance =
  Balance -> NonEmpty Float
handler Balance
balance
  where
    handler :: Balance -> NonEmpty Float
handler =
      if (Float
maxTotal Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Balance -> Float
balanceTotal Balance
balance) Bool -> Bool -> Bool
&& Balance -> Bool
hasUnbounded Balance
balance
      then Balance -> NonEmpty Float
distributeOnUnbounded
      else Balance -> NonEmpty Float
distributeOnAll
    maxTotal :: Float
maxTotal = [Float] -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum ([Maybe Float] -> [Float]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe Float] -> [Float]) -> [Maybe Float] -> [Float]
forall a b. (a -> b) -> a -> b
$ NonEmpty (Maybe Float) -> [Maybe Float]
forall a. NonEmpty a -> [a]
NonEmpty.toList (NonEmpty (Maybe Float) -> [Maybe Float])
-> NonEmpty (Maybe Float) -> [Maybe Float]
forall a b. (a -> b) -> a -> b
$ Balance -> NonEmpty (Maybe Float)
balanceMax Balance
balance)

roundSizes :: NonEmpty Float -> NonEmpty Int
roundSizes :: NonEmpty Float -> NonEmpty Int
roundSizes (Float
head' :| [Float]
tail') =
  Int
roundedHead Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Float -> Int
float2Int Float
surplus) Int -> [Int] -> NonEmpty Int
forall a. a -> [a] -> NonEmpty a
:| [Int]
roundedTail
  where
    (Float
surplus, [Int]
roundedTail) = (Float -> Float -> (Float, Int))
-> Float -> [Float] -> (Float, [Int])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
mapAccumL Float -> Float -> (Float, Int)
folder Float
diff0 [Float]
tail'
    (Int
roundedHead, Float
diff0) = Float -> (Int, Float)
diff Float
head'
    folder :: Float -> Float -> (Float, Int)
folder Float
z Float
a =
      (Float
z Float -> Float -> Float
forall a. Num a => a -> a -> a
+ Float
z1, Int
a1)
      where
        (Int
a1, Float
z1) = Float -> (Int, Float)
diff Float
a
    diff :: Float -> (Int, Float)
diff Float
a = (Float -> Int
floorFloatInt Float
a, Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
- Int -> Float
int2Float (Float -> Int
forall a b. (RealFrac a, Integral b) => a -> b
floor Float
a))

ensureMinimum2 :: NonEmpty Float -> NonEmpty Float
ensureMinimum2 :: NonEmpty Float -> NonEmpty Float
ensureMinimum2 NonEmpty Float
sizes =
  Float -> Float
choose (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty Float
positives
  where
    positive :: Float -> Float
positive = Float -> Float -> Float
forall a. Ord a => a -> a -> a
max Float
0
    positives :: NonEmpty Float
positives = Float -> Float
positive (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty Float
sizes
    positivesCount :: Int
positivesCount = [Float] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Float] -> Int) -> [Float] -> Int
forall a b. (a -> b) -> a -> b
$ (Float -> Bool) -> NonEmpty Float -> [Float]
forall a. (a -> Bool) -> NonEmpty a -> [a]
NonEmpty.filter (Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
2) NonEmpty Float
sizes
    unders :: NonEmpty Float
unders = Float -> Float
amountUnderTwo (Float -> Float) -> NonEmpty Float -> NonEmpty Float
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty Float
positives
    sub :: Float
sub = NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
unders Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Int -> Float
int2Float Int
positivesCount
    amountUnderTwo :: Float -> Float
amountUnderTwo Float
a = Float -> Float
positive (Float
2 Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
a)
    choose :: Float -> Float
choose Float
a = Float -> Float -> Float
forall a. Ord a => a -> a -> a
max Float
2 (Float
a Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
sub)

rectifySizes :: NonEmpty Float -> NonEmpty Int
rectifySizes :: NonEmpty Float -> NonEmpty Int
rectifySizes =
  NonEmpty Float -> NonEmpty Int
roundSizes (NonEmpty Float -> NonEmpty Int)
-> (NonEmpty Float -> NonEmpty Float)
-> NonEmpty Float
-> NonEmpty Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty Float -> NonEmpty Float
ensureMinimum2

-- FIXME need to round manually, keeping track of the surplus, in order to achieve determinism
balanceSizes :: NonEmpty Float -> NonEmpty (Maybe Float) -> NonEmpty Float -> NonEmpty Bool -> Float -> NonEmpty Int
balanceSizes :: NonEmpty Float
-> NonEmpty (Maybe Float)
-> NonEmpty Float
-> NonEmpty Bool
-> Float
-> NonEmpty Int
balanceSizes NonEmpty Float
minSizes NonEmpty (Maybe Float)
maxSizes NonEmpty Float
weights NonEmpty Bool
minimized Float
total =
  NonEmpty Float -> NonEmpty Int
rectifySizes (Balance -> NonEmpty Float
fit Balance
balance)
  where
    fit :: Balance -> NonEmpty Float
fit = if NonEmpty Float -> Float
forall a (f :: * -> *). (Foldable f, Num a) => f a -> a
sum NonEmpty Float
minSizes Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
> Float
total then Balance -> NonEmpty Float
cutSizes else Balance -> NonEmpty Float
distributeSizes
    balance :: Balance
balance = NonEmpty Float
-> NonEmpty (Maybe Float)
-> NonEmpty Float
-> NonEmpty Bool
-> Float
-> Balance
Balance NonEmpty Float
minSizes NonEmpty (Maybe Float)
maxSizes NonEmpty Float
weights NonEmpty Bool
minimized Float
total