Skip to content

Commit

Permalink
added HiGHS; then disabled it because this package doesn't support IL…
Browse files Browse the repository at this point in the history
…Ps through it
  • Loading branch information
dpvanbalen committed Jun 7, 2024
1 parent 9424d5b commit 7022acd
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 100 deletions.
4 changes: 4 additions & 0 deletions accelerate.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ library
, base-orphans >= 0.3
, bifunctors
, bytestring >= 0.10.2
-- , comfort-array >= 0.5.5
, composition
, containers >= 0.3
, deepseq >= 1.3
Expand All @@ -354,6 +355,8 @@ library
, hashable >= 1.1
, hashtables >= 1.2.3
, hedgehog >= 0.5
-- , highs-lp >= 0.0
-- , linear-programming >= 0.0.0.1
, microlens >= 0.4
, microlens-th >= 0.4
, microlens-mtl >= 0.2
Expand Down Expand Up @@ -456,6 +459,7 @@ library
Data.Array.Accelerate.Trafo.Partitioning.ILP.Clustering
Data.Array.Accelerate.Trafo.Partitioning.ILP.Graph
Data.Array.Accelerate.Trafo.Partitioning.ILP.Labels
-- Data.Array.Accelerate.Trafo.Partitioning.ILP.HiGHS
Data.Array.Accelerate.Trafo.Partitioning.ILP.MIP
Data.Array.Accelerate.Trafo.Partitioning.ILP.NameGeneration
Data.Array.Accelerate.Trafo.Partitioning.ILP.Solve
Expand Down
2 changes: 2 additions & 0 deletions src/Data/Array/Accelerate/Trafo.hs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ import Data.Array.Accelerate.Trafo.Partitioning.ILP.Solve (Objective(..))
import Data.Array.Accelerate.Trafo.NewNewFusion (Benchmarking)

defaultObjective = IntermediateArrays
-- TODO: so much duplication here, and I keep worrying that there are differences hiding in one of them.
-- need to abstract a bit!

test
:: forall sched kernel f. (Afunction f, DesugarAcc (KernelOperation kernel), Operation.SimplifyOperation (KernelOperation kernel), Operation.SLVOperation (KernelOperation kernel), Partitioning.MakesILP (KernelOperation kernel), Pretty.PrettyOp (KernelOperation kernel), Pretty.PrettyKernel kernel, IsSchedule sched, IsKernel kernel, Pretty.PrettySchedule sched, Operation.ShrinkArg (Partitioning.BackendClusterArg (KernelOperation kernel)))
Expand Down
8 changes: 6 additions & 2 deletions src/Data/Array/Accelerate/Trafo/NewNewFusion.hs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import Data.Array.Accelerate.Trafo.Partitioning.ILP
import Data.Array.Accelerate.Trafo.Partitioning.ILP.Graph (MakesILP)
import qualified Data.Array.Accelerate.Pretty.Operation as Pretty
import Data.Array.Accelerate.Trafo.Partitioning.ILP.Solve (Objective (..))
-- import Data.Array.Accelerate.Trafo.Partitioning.ILP.HiGHS (HiGHS(..))


#ifdef ACCELERATE_DEBUG
Expand All @@ -61,6 +62,9 @@ convertAccBenchF greedydir = withSimplStats (greedyF greedydir FusedEdges)
-- Array Fusion
-- ============

defaultSolver =
MIPSolver Gurobi

-- | Apply the fusion transformation to a de Bruijn AST
--
convertAccWith
Expand All @@ -69,7 +73,7 @@ convertAccWith
-> Objective
-> OperationAcc op () a
-> PartitionedAcc op () a
convertAccWith _ = withSimplStats cbcFusion
convertAccWith _ = withSimplStats (ilpFusion'' defaultSolver)

convertAcc :: (HasCallStack, MakesILP op, Pretty.PrettyOp (Cluster op)) => Objective -> OperationAcc op () a -> PartitionedAcc op () a
convertAcc = convertAccWith defaultOptions
Expand All @@ -80,7 +84,7 @@ convertAfun :: (HasCallStack, MakesILP op, Pretty.PrettyOp (Cluster op)) => Obje
convertAfun = convertAfunWith defaultOptions

convertAfunWith :: (HasCallStack, MakesILP op, Pretty.PrettyOp (Cluster op)) => Config -> Objective -> OperationAfun op () f -> PartitionedAfun op () f
convertAfunWith _ = withSimplStats cbcFusionF
convertAfunWith _ = withSimplStats (ilpFusionF'' defaultSolver)


withSimplStats :: a -> a
Expand Down
70 changes: 48 additions & 22 deletions src/Data/Array/Accelerate/Trafo/Partitioning/ILP.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,65 @@ import Data.Array.Accelerate.AST.Partitioned
import Data.Array.Accelerate.AST.Operation
( OperationAcc, OperationAfun )
import Data.Array.Accelerate.Trafo.Partitioning.ILP.Solver
( ILPSolver(solve), (.==.), int )
( ILPSolver, solve, (.==.), int )
import Data.Array.Accelerate.Trafo.Partitioning.ILP.MIP
( cbc, cplex, glpsol, gurobiCl, lpSolve, scip )
( cbc, cplex, glpsol, gurobiCl, lpSolve, scip, MIP(..) )

import System.IO.Unsafe (unsafePerformIO)
import Data.Array.Accelerate.Trafo.Partitioning.ILP.Labels (Label)
import Data.Map (Map)
import qualified Data.Array.Accelerate.Pretty.Operation as Pretty
import Data.Function ((&))
import qualified Data.Set as Set
import Lens.Micro ((^.), (%~), (<>~), (.~))
import Lens.Micro ((^.), (<>~))
import Data.Maybe (isJust)
-- import Data.Array.Accelerate.Trafo.Partitioning.ILP.HiGHS (HiGHS(Highs))

data Benchmarking = GreedyUp | GreedyDown | NoFusion
deriving (Show, Eq)
deriving (Show, Eq, Bounded, Enum)

-- data type that should probably be in the options
data Solver = MIPSolver MIPSolver -- | HiGHS
data MIPSolver = CBC | Gurobi | CPLEX | GLPSOL | LPSOLVE | SCIP

ilpFusion'' :: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Solver -> Objective -> OperationAcc op () a -> PartitionedAcc op () a
ilpFusion'' (MIPSolver s) = case s of
CBC -> ilpFusion (MIP cbc)
Gurobi -> ilpFusion (MIP gurobiCl)
CPLEX -> ilpFusion (MIP cplex)
GLPSOL -> ilpFusion (MIP glpsol)
LPSOLVE -> ilpFusion (MIP lpSolve)
SCIP -> ilpFusion (MIP scip)
-- ilpFusion'' HiGHS = ilpFusion Highs


ilpFusionF'' :: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Solver -> Objective -> OperationAfun op () a -> PartitionedAfun op () a
ilpFusionF'' (MIPSolver s) = case s of
CBC -> ilpFusionF (MIP cbc)
Gurobi -> ilpFusionF (MIP gurobiCl)
CPLEX -> ilpFusionF (MIP cplex)
GLPSOL -> ilpFusionF (MIP glpsol)
LPSOLVE -> ilpFusionF (MIP lpSolve)
SCIP -> ilpFusionF (MIP scip)
-- ilpFusionF'' HiGHS = ilpFusionF Highs

cbcFusion, gurobiFusion, cplexFusion, glpsolFusion, lpSolveFusion, scipFusion
:: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Objective -> OperationAcc op () a -> PartitionedAcc op () a
cbcFusion = ilpFusion cbc
gurobiFusion = ilpFusion gurobiCl
cplexFusion = ilpFusion cplex
glpsolFusion = ilpFusion glpsol
lpSolveFusion = ilpFusion lpSolve
scipFusion = ilpFusion scip
cbcFusion = ilpFusion (MIP cbc)
gurobiFusion = ilpFusion (MIP gurobiCl)
cplexFusion = ilpFusion (MIP cplex)
glpsolFusion = ilpFusion (MIP glpsol)
lpSolveFusion = ilpFusion (MIP lpSolve)
scipFusion = ilpFusion (MIP scip)

cbcFusionF, gurobiFusionF, cplexFusionF, glpsolFusionF, lpSolveFusionF, scipFusionF
:: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Objective -> OperationAfun op () a -> PartitionedAfun op () a
cbcFusionF = ilpFusionF cbc
gurobiFusionF = ilpFusionF gurobiCl
cplexFusionF = ilpFusionF cplex
glpsolFusionF = ilpFusionF glpsol
lpSolveFusionF = ilpFusionF lpSolve
scipFusionF = ilpFusionF scip
cbcFusionF = ilpFusionF (MIP cbc)
gurobiFusionF = ilpFusionF (MIP gurobiCl)
cplexFusionF = ilpFusionF (MIP cplex)
glpsolFusionF = ilpFusionF (MIP glpsol)
lpSolveFusionF = ilpFusionF (MIP lpSolve)
scipFusionF = ilpFusionF (MIP scip)

ilpFusion :: (MakesILP op, ILPSolver s op, Pretty.PrettyOp (Cluster op)) => s -> Objective -> OperationAcc op () a -> PartitionedAcc op () a
ilpFusion = ilpFusion' makeFullGraph (reconstruct False)
Expand Down Expand Up @@ -116,12 +142,12 @@ greedyFusion' :: forall s op x y. (MakesILP op, ILPSolver s op)
greedyFusion' k1 k2 s b obj acc = fusedAcc
where
(info'@(Info graph _ _), constrM') = k1 acc
nedges = graph^.fusibleEdges & Set.size
nedges = (graph^.fusibleEdges) Set.\\ (graph^.infusibleEdges) & Set.size
go :: Int -> Information op -> Information op
go n info -- loop over all fusible edges. Try to set the current one to fused, if there's still a legal solution, keep it fused and continue.
| n >= nedges = info
| otherwise = let
i:->j = graph^.fusibleEdges&Set.elemAt (case b of
i:->j = (graph^.fusibleEdges) Set.\\ (graph^.infusibleEdges)&Set.elemAt (case b of
GreedyUp -> n
GreedyDown -> nedges - n - 1)
info'' = info&constr<>~(fused i j .==. int 0)
Expand All @@ -143,13 +169,13 @@ greedyFusion' k1 k2 s b obj acc = fusedAcc
Just y -> y

greedy :: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Benchmarking -> Objective -> OperationAcc op () a -> PartitionedAcc op () a
greedy = greedyFusion gurobiCl
greedy = greedyFusion (MIP gurobiCl)
no :: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Objective -> OperationAcc op () a -> PartitionedAcc op () a
no = noFusion gurobiCl
no = noFusion (MIP gurobiCl)
greedyF :: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Benchmarking -> Objective -> OperationAfun op () a -> PartitionedAfun op () a
greedyF = greedyFusionF gurobiCl
greedyF = greedyFusionF (MIP gurobiCl)
noF :: (MakesILP op, Pretty.PrettyOp (Cluster op)) => Objective -> OperationAfun op () a -> PartitionedAfun op () a
noF = noFusionF gurobiCl
noF = noFusionF (MIP gurobiCl)
greedyFusion :: (MakesILP op, ILPSolver s op, Pretty.PrettyOp (Cluster op)) => s -> Benchmarking -> Objective -> OperationAcc op () a -> PartitionedAcc op () a
greedyFusion = greedyFusion' makeFullGraph (reconstruct False)
greedyFusionF :: (MakesILP op, ILPSolver s op, Pretty.PrettyOp (Cluster op)) => s -> Benchmarking -> Objective -> OperationAfun op () a -> PartitionedAfun op () a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,12 @@ openReconstructF :: MakesILP op
openReconstructF a b c d l e f = (\(Right x) -> x) $ openReconstruct' a b c d (Just l) e f

openReconstruct' :: forall op aenv. MakesILP op => Bool -> LabelEnv aenv -> Graph -> [ClusterLs] -> Maybe Label -> M.Map Label [ClusterLs] -> M.Map Label (Construction op) -> Either (Exists (PreOpenAcc (Clustered op) aenv)) (Exists (PreOpenAfun (Clustered op) aenv))
openReconstruct' singletons labelenv graph clusterslist mlab subclustersmap construct = case mlab of
openReconstruct' singletons labelenv graph clusterslist mlab subclustersmap construct =
Debug.Trace.traceShow ("number of execs:", M.size $ M.filter (\case
CExe{} -> True
CExe'{} -> True
_ -> False) construct) $
case mlab of
Just l -> Right $ makeASTF labelenv l mempty
Nothing -> Left $ makeAST labelenv clusters mempty
where
Expand Down
2 changes: 1 addition & 1 deletion src/Data/Array/Accelerate/Trafo/Partitioning/ILP/Graph.hs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ mkFullGraph (Exec op args) = do
lenv %= flip (updateLabelEnv args) l -- replace the labels of the buffers of output arrays with l
let labelledArgs = getLabelArgs args env -- uses the old env! Notably, gets the Alloc (or its lhs?) for empty arrays, and the previous writer for Permute
let fuseedges = S.map (-?> l) $ getInputArgLabels args env -- add fusible edges to all inputs
let nonfuseedges = S.map (-?> l) $ getOutputArgLabels args env
let nonfuseedges = S.map (-?> l) $ getOutputArgLabels args env -- add infusible edges to the allocator/last user of the previous value in the buffer we use for output
let backInfo = mkGraph op labelledArgs l -- query the backend for its fusion information - we add l and fuseedges next line
return $ FGRes (backInfo
& graphI.graphNodes %~ S.insert l
Expand Down
68 changes: 68 additions & 0 deletions src/Data/Array/Accelerate/Trafo/Partitioning/ILP/HiGHS.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ViewPatterns #-}
module Data.Array.Accelerate.Trafo.Partitioning.ILP.HiGHS where
import Data.Array.Accelerate.Trafo.Partitioning.ILP.Solver
import Data.Array.Accelerate.Trafo.Partitioning.ILP.Graph (MakesILP)

import qualified Numeric.HiGHS.LP as LP
import Numeric.LinearProgramming.Common
import GHC.Float (int2Double)
import qualified Data.Map as M
import Data.Array.Comfort.Storable
import qualified Debug.Trace

-- DON'T USE
-- Even though HiGHS is also capable of MIP problems,
-- the highs-lp package only supports LP.
-- This is useless for us; we need ILP/MIP support.
-- Keeping this here in case we get around to forking highs-lp with ILP support.


data HiGHS = Highs

instance MakesILP op => ILPSolver HiGHS op where
solvePartial Highs ilp@(ILP dir cost constraint bounds n) = pure . getSolution $
LP.solve LP.choose bounds' constraint' (dir', cost')
where
vs = allVars ilp
bounds' = highbounds bounds []
constraint' = highconstraints n constraint []
dir' = case dir of
Maximise -> LP.Maximize
Minimise -> LP.Minimize
cost' = case highexpr n cost of (term,_constant) -> fromMap . M.unionWith (+) (M.fromSet (const 0) vs) $ term2Map term

getSolution (s, Nothing) = Debug.Trace.traceShow s Nothing
getSolution (s, Just (c,arr)) = Debug.Trace.traceShow (s,c) $ Just (round <$> toMap arr)

term2Map [] = mempty
term2Map ((Term d v):ts) = M.unionWith (+) (M.singleton v d) (term2Map ts)

highbounds NoBounds = id
highbounds (a :<> b) = highbounds a . highbounds b
highbounds (Binary v) = (:) $ Inequality v $ Between 0 1
highbounds (LowerUpper l v u) = (:) $ Inequality v $ Between (int2Double l) (int2Double u)
highbounds (Lower l v) = (:) $ Inequality v $ GreaterEqual (int2Double l)
highbounds (Upper v u) = (:) $ Inequality v $ LessEqual (int2Double u)

highconstraints n TrueConstraint = id
highconstraints n (a :&& b) = highconstraints n a . highconstraints n b
highconstraints n ((a :>= b)) = (:) $ case (highexpr n (a.-.b)) of (terms,((-1)*)-> c) -> Inequality terms $ GreaterEqual (int2Double c)
highconstraints n ((a :== b)) = (:) $ case (highexpr n (a.-.b)) of (terms,((-1)*)-> c) -> Inequality terms $ Equal (int2Double c)
highconstraints n ((a :<= b)) = (:) $ case (highexpr n (a.-.b)) of (terms,((-1)*)-> c) -> Inequality terms $ LessEqual (int2Double c)

highexpr n (Constant (Number m)) = ([],m n)
highexpr n ((Number m) :* v) = ([int2Double (m n) .* v],0)
highexpr n (a :+ b) = case (highexpr n a, highexpr n b) of
((t1,c),(t2,d)) -> (t1 `merge` t2,c+d)
where
merge [] xs = xs
merge xs [] = xs
merge (Term a x:xs) (Term b y:ys)
| x == y = Term (a+b) x : merge xs ys
| x < y = Term a x : merge xs (Term b y:ys)
| y < x = Term b y : merge (Term a x:xs) ys
| otherwise = error "simple math"

2 changes: 1 addition & 1 deletion src/Data/Array/Accelerate/Trafo/Partitioning/ILP/Labels.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ data Label = Label
makeLenses ''Label
instance Show Label where
-- show = ("Label"<>) . show . _labelId
show (Label i p) = show i -- "L" <> show i <> "{" <> show p <> "} "
show (Label i p) = "L" <> show i <> "{" <> show p <> "} "
instance Eq Label where
(Label x a) == (Label y b)
| x == y = if a == b then True else error $ "same labelId but different parents: " <> show x <> show a <> " - " <> show b
Expand Down
Loading

0 comments on commit 7022acd

Please sign in to comment.