Skip to content

Commit e24bc64

Browse files
committed
wip
1 parent f48f135 commit e24bc64

File tree

4 files changed

+1136
-19
lines changed

4 files changed

+1136
-19
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
*~
33
dist-*/
44
.vscode/*
5+
.direnv/*
6+
.envrc

src/Linear/Simplex/Solver/TwoPhase.hs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,27 @@
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

1636
import 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
412434
twoPhaseSimplex' :: (MonadIO m, MonadLogger m) => VarDomainMap -> ObjectiveFunction -> [PolyConstraint] -> m (Maybe Result)
413435
twoPhaseSimplex' 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.
434476
preprocess :: ObjectiveFunction

src/Linear/Simplex/Types.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ data VarDomain
129129
= NonNegative -- ^ var >= 0 (standard simplex assumption, no transformation needed)
130130
| LowerBound SimplexNum -- ^ var >= L for some L (if L < 0: shift, if L > 0: add constraint)
131131
| Unbounded -- ^ No lower bound (split into difference of two non-negative vars)
132+
-- TODO: Upperbound can still be useful, can negate it to get a loewr bound, can add it to the constraints
132133
deriving stock (Show, Read, Eq, Generic)
133134

134135
-- | Map from variables to their domain specifications.

0 commit comments

Comments
 (0)