1111-- 'optimizeFeasibleSystem' performs phase two of the two-phase simplex method.
1212-- 'twoPhaseSimplex' performs both phases of the two-phase simplex method.
1313-- 'twoPhaseSimplex'' performs both phases with variable domain support.
14- module Linear.Simplex.Solver.TwoPhase (findFeasibleSolution , optimizeFeasibleSystem , twoPhaseSimplex , twoPhaseSimplex' ) where
14+ module Linear.Simplex.Solver.TwoPhase
15+ ( findFeasibleSolution
16+ , optimizeFeasibleSystem
17+ , twoPhaseSimplex
18+ , twoPhaseSimplex'
19+ -- Internal functions exported for testing
20+ , preprocess
21+ , postprocess
22+ , computeObjective
23+ , collectAllVars
24+ , generateTransform
25+ , getTransform
26+ , applyTransforms
27+ , applyTransform
28+ , applyShiftToObjective
29+ , applyShiftToConstraint
30+ , applySplitToObjective
31+ , applySplitToConstraint
32+ , unapplyTransforms
33+ , unapplyTransform
34+ ) where
1535
1636import Prelude hiding (EQ )
1737
@@ -409,11 +429,13 @@ twoPhaseSimplex objFunction unsimplifiedSystem = do
409429-- | Perform the two phase simplex method with variable domain information.
410430-- Variables not in the VarDomainMap are assumed to be Unbounded (no lower bound).
411431-- This function applies necessary transformations before solving and unapplies them after.
432+ -- The returned Result contains variable values and objective value in the original space.
433+ -- TODO: use this as twoPhaseSimplex, add instructions in CHANGELOG for old users
412434twoPhaseSimplex' :: (MonadIO m , MonadLogger m ) => VarDomainMap -> ObjectiveFunction -> [PolyConstraint ] -> m (Maybe Result )
413435twoPhaseSimplex' domainMap objFunction constraints = do
414436 logMsg LevelInfo $
415437 " twoPhaseSimplex': Solving system with domain map " <> showT domainMap
416- let (transformedObj, transformedConstraints, transforms) = preprocess objFunction domainMap constraints
438+ let (transformedObj, transformedConstraints, transforms) = preprocess objFunction domainMap constraints
417439 logMsg LevelInfo $
418440 " twoPhaseSimplex': Applied transforms " <> showT transforms
419441 <> " ; Transformed objective: " <> showT transformedObj
@@ -424,11 +446,31 @@ twoPhaseSimplex' domainMap objFunction constraints = do
424446 logMsg LevelInfo " twoPhaseSimplex': No solution found"
425447 pure Nothing
426448 Just result -> do
427- let finalResult = unapplyTransforms transforms result
449+ let finalResult = postprocess objFunction transforms result
428450 logMsg LevelInfo $
429- " twoPhaseSimplex': Unapplied transforms, final result: " <> showT finalResult
451+ " twoPhaseSimplex': Postprocessed result: " <> showT finalResult
430452 pure (Just finalResult)
431453
454+ -- | Postprocess the result by unapplying variable transformations and computing
455+ -- the objective value in the original space.
456+ postprocess :: ObjectiveFunction -> [VarTransform ] -> Result -> Result
457+ postprocess objFunction transforms result =
458+ let -- First unapply transforms to get variable values in original space
459+ unappliedResult = unapplyTransforms transforms result
460+ -- Then compute the objective value using the original objective function
461+ objVal = computeObjective objFunction unappliedResult. varValMap
462+ -- Update the objective value in the result
463+ finalVarValMap = M. insert unappliedResult. objectiveVar objVal unappliedResult. varValMap
464+ in unappliedResult { varValMap = finalVarValMap }
465+
466+ -- | Compute the value of an objective function given variable values.
467+ computeObjective :: ObjectiveFunction -> M. Map Var SimplexNum -> SimplexNum
468+ computeObjective objFunction varVals =
469+ let coeffs = case objFunction of
470+ Max m -> m
471+ Min m -> m
472+ in sum $ map (\ (var, coeff) -> coeff * M. findWithDefault 0 var varVals) (M. toList coeffs)
473+
432474-- | Preprocess the system by applying variable transformations based on domain information.
433475-- Returns the transformed objective, constraints, and the list of transforms applied.
434476preprocess :: ObjectiveFunction
0 commit comments