-- | Classical results: 
--
-- * Hilbert's degree formula
--
-- * some enumarative geometry computations by Schubert
--

{-# LANGUAGE BangPatterns, TypeSynonymInstances, FlexibleInstances #-}

module Math.RootLoci.Classic where

--------------------------------------------------------------------------------

import Data.List

import Control.Monad

import Math.Combinat.Numbers
import Math.Combinat.Sign
import Math.Combinat.Partitions.Integer
import Math.Combinat.Sets

--------------------------------------------------------------------------------

-- | Codimension of a strata. This is simply @(sum mu_i) - length(mu)@.
codim :: Partition -> Int
codim (Partition ps) = sum ps - length ps

-- | Dimension of the strata. @dim = length(mu)@.
dimension :: Partition -> Int
dimension (Partition ps) = length ps

--------------------------------------------------------------------------------
-- * Hilbert formula

-- | Hilbert's formula for the degree of a stratum
hilbert :: Partition -> Integer
hilbert part@(Partition ps) = div numer denom where

  n = sum    ps
  d = length ps

  numer = factorial d * product (map fi ps)          -- d! * prod (nu_i)
  denom = product (map (factorial . snd) ies)        -- prod (e_r!)
 
  ies = toExponentialForm part      -- (r,e_r) pairs
   
  fi :: Int -> Integer
  fi = fromIntegral

-- | Hilbert's degree formula, another version (as a sanity test).
hilbert2 :: Partition -> Integer
hilbert2 part@(Partition ps) = div numer denom where

  -- this is from FNR, opposite notation (d and n are swapped!)
  -- just to be really sure about the formula :)

  n = sum es
  d = sum [ i*ei | (i,ei) <- toExponentialForm part ]
  es =    [ ei   | (i,ei) <- toExponentialForm part ]

  numer = factorial n * product [ (fi i)^ei | (i,ei) <- toExponentialForm part ]
  denom = product [ factorial ei | (i,ei) <- toExponentialForm part ]

  fi :: Int -> Integer
  fi = fromIntegral
   
-- check_hilbert2 :: Bool   
-- check_hilbert2 = and [ hilbert p == hilbert2 p | n<-[0..20] , p<-partitions n ]

--------------------------------------------------------------------------------
-- * Schubert

-- | Number of 4-tangent lines to a generic degree @d@ surface 
quadTangentLines :: Int -> Integer
quadTangentLines d0
  | d < 8     = 0
  | otherwise = d * (d - 4) * (d - 5) * (d - 6) * (d - 7) * (d^3 + 6*d^2 + 7*d - 30)
  where
    d = fromIntegral d0 :: Integer

-- | Number of lines meeting a generic degree @d@ surface at point with 5x multiplicity
quintFlexLines :: Int -> Integer
quintFlexLines d0
  | d < 5     = 0
  | otherwise = error "quintFlexLines"
  where
    d = fromIntegral d0 :: Integer

--------------------------------------------------------------------------------