chore: examAutoOccurrence converted to Either
This commit is contained in:
parent
59f5bd3591
commit
e03326e1ac
@ -2800,9 +2800,14 @@ BtnExamAutoOccurrenceNudgeUp: +
|
|||||||
BtnExamAutoOccurrenceNudgeDown: -
|
BtnExamAutoOccurrenceNudgeDown: -
|
||||||
ExamRoomMappingSurname: Nachnamen beginnend mit
|
ExamRoomMappingSurname: Nachnamen beginnend mit
|
||||||
ExamRoomMappingMatriculation: Matrikelnummern endend in
|
ExamRoomMappingMatriculation: Matrikelnummern endend in
|
||||||
|
ExamRoomMappingRandom: Zufällige Zuordnung
|
||||||
ExamRoomLoad: Auslastung
|
ExamRoomLoad: Auslastung
|
||||||
ExamRegisteredCount: Anmeldungen
|
ExamRegisteredCount: Anmeldungen
|
||||||
ExamRegisteredCountOf num@Int64 count@Int64: #{num}/#{count}
|
ExamRegisteredCountOf num@Int64 count@Int64: #{num}/#{count}
|
||||||
|
ExamAutoOccurrenceExceptionRuleNoOp: Keine Automatische Verteilung gewählt
|
||||||
|
ExamAutoOccurrenceExceptionNotEnoughSpace: Nicht ausreichend Platz
|
||||||
|
ExamAutoOccurrenceExceptionNoUsers: Keine Nutzer
|
||||||
|
ExamAutoOccurrenceExceptionRoomTooSmall: Automatische Verteilung gescheitert. Es kann helfen kleine Räume zu entfernen.
|
||||||
|
|
||||||
NoFilter: Keine Einschränkung
|
NoFilter: Keine Einschränkung
|
||||||
|
|
||||||
|
|||||||
@ -2800,9 +2800,14 @@ BtnExamAutoOccurrenceNudgeUp: +
|
|||||||
BtnExamAutoOccurrenceNudgeDown: -
|
BtnExamAutoOccurrenceNudgeDown: -
|
||||||
ExamRoomMappingSurname: Surnames starting with
|
ExamRoomMappingSurname: Surnames starting with
|
||||||
ExamRoomMappingMatriculation: Matriculation numbers ending in
|
ExamRoomMappingMatriculation: Matriculation numbers ending in
|
||||||
|
ExamRoomMappingRandom: Random assignment
|
||||||
ExamRoomLoad: Utilisation
|
ExamRoomLoad: Utilisation
|
||||||
ExamRegisteredCount: Registrations
|
ExamRegisteredCount: Registrations
|
||||||
ExamRegisteredCountOf num count: #{num}/#{count}
|
ExamRegisteredCountOf num count: #{num}/#{count}
|
||||||
|
ExamAutoOccurrenceExceptionRuleNoOp: Didn't chose an automatic distribution
|
||||||
|
ExamAutoOccurrenceExceptionNotEnoughSpace: Not enough space
|
||||||
|
ExamAutoOccurrenceExceptionNoUsers: No participants
|
||||||
|
ExamAutoOccurrenceExceptionRoomTooSmall: Automatic distribution failed. Removing small rooms might help.
|
||||||
|
|
||||||
NoFilter: No restriction
|
NoFilter: No restriction
|
||||||
|
|
||||||
|
|||||||
@ -162,6 +162,8 @@ dependencies:
|
|||||||
- nonce
|
- nonce
|
||||||
- IntervalMap
|
- IntervalMap
|
||||||
- haskell-src-meta
|
- haskell-src-meta
|
||||||
|
- either
|
||||||
|
|
||||||
other-extensions:
|
other-extensions:
|
||||||
- GeneralizedNewtypeDeriving
|
- GeneralizedNewtypeDeriving
|
||||||
- IncoherentInstances
|
- IncoherentInstances
|
||||||
|
|||||||
@ -47,6 +47,8 @@ import qualified Data.Array.ST as ST
|
|||||||
import Data.List (findIndex, unfoldr)
|
import Data.List (findIndex, unfoldr)
|
||||||
import qualified Data.List as List
|
import qualified Data.List as List
|
||||||
|
|
||||||
|
import Data.Either.Combinators (maybeToRight)
|
||||||
|
|
||||||
import Data.ExtendedReal
|
import Data.ExtendedReal
|
||||||
import Data.Ratio (Ratio)
|
import Data.Ratio (Ratio)
|
||||||
|
|
||||||
@ -256,6 +258,16 @@ deriveJSON defaultOptions
|
|||||||
{ fieldLabelModifier = camelToPathPiece' 1
|
{ fieldLabelModifier = camelToPathPiece' 1
|
||||||
} ''ExamAutoOccurrenceConfig
|
} ''ExamAutoOccurrenceConfig
|
||||||
|
|
||||||
|
data ExamAutoOccurrenceException
|
||||||
|
= ExamAutoOccurrenceExceptionRuleNoOp
|
||||||
|
| ExamAutoOccurrenceExceptionNotEnoughSpace
|
||||||
|
| ExamAutoOccurrenceExceptionNoUsers
|
||||||
|
| ExamAutoOccurrenceExceptionRoomTooSmall
|
||||||
|
deriving (Show, Generic, Typeable)
|
||||||
|
|
||||||
|
instance Exception ExamAutoOccurrenceException
|
||||||
|
|
||||||
|
embedRenderMessage ''UniWorX ''ExamAutoOccurrenceException id
|
||||||
|
|
||||||
examAutoOccurrence :: forall seed.
|
examAutoOccurrence :: forall seed.
|
||||||
Hashable seed
|
Hashable seed
|
||||||
@ -264,16 +276,20 @@ examAutoOccurrence :: forall seed.
|
|||||||
-> ExamAutoOccurrenceConfig
|
-> ExamAutoOccurrenceConfig
|
||||||
-> Map ExamOccurrenceId Natural
|
-> Map ExamOccurrenceId Natural
|
||||||
-> Map UserId (User, Maybe ExamOccurrenceId)
|
-> Map UserId (User, Maybe ExamOccurrenceId)
|
||||||
-> (Maybe (ExamOccurrenceMapping ExamOccurrenceId), Map UserId (Maybe ExamOccurrenceId))
|
-> Either ExamAutoOccurrenceException (ExamOccurrenceMapping ExamOccurrenceId, Map UserId (Maybe ExamOccurrenceId))
|
||||||
examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences users
|
examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences users
|
||||||
| sum occurrences' < usersCount
|
| sum occurrences' < usersCount
|
||||||
|| sum occurrences' <= 0
|
|| sum occurrences' <= 0
|
||||||
|| Map.null users'
|
= Left ExamAutoOccurrenceExceptionNotEnoughSpace
|
||||||
= nullResult
|
| Map.null users'
|
||||||
|
= Left ExamAutoOccurrenceExceptionNoUsers
|
||||||
| otherwise
|
| otherwise
|
||||||
= case rule of
|
= case rule of
|
||||||
ExamRoomRandom
|
ExamRoomRandom
|
||||||
-> ( Nothing
|
-> Right ( ExamOccurrenceMapping {
|
||||||
|
examOccurrenceMappingRule=rule,
|
||||||
|
examOccurrenceMappingMapping=Map.fromList $ (set _2 $ Set.singleton ExamOccurrenceMappingRandom) <$> occurrences''
|
||||||
|
}
|
||||||
, Map.union (view _2 <$> assignedUsers) randomlyAssignedUsers
|
, Map.union (view _2 <$> assignedUsers) randomlyAssignedUsers
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
@ -307,13 +323,8 @@ examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences
|
|||||||
where
|
where
|
||||||
newUsers, remainingUsers :: [UserId]
|
newUsers, remainingUsers :: [UserId]
|
||||||
(newUsers, remainingUsers) = List.genericSplitAt roomSize userList
|
(newUsers, remainingUsers) = List.genericSplitAt roomSize userList
|
||||||
_ | Just (postprocess -> (resMapping, result)) <- bestOption
|
_ -> bimap (ExamOccurrenceMapping rule) (Map.unionWith (<|>) (view _2 <$> users)) . postprocess <$> bestOption
|
||||||
-> ( Just $ ExamOccurrenceMapping rule resMapping
|
|
||||||
, Map.unionWith (<|>) (view _2 <$> users) result
|
|
||||||
)
|
|
||||||
_ -> nullResult
|
|
||||||
where
|
where
|
||||||
nullResult = (Nothing, view _2 <$> users)
|
|
||||||
usersCount :: forall a. Num a => a
|
usersCount :: forall a. Num a => a
|
||||||
usersCount = getSum $ foldMap (Sum . fromIntegral . Set.size) users'
|
usersCount = getSum $ foldMap (Sum . fromIntegral . Set.size) users'
|
||||||
|
|
||||||
@ -519,13 +530,13 @@ examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences
|
|||||||
|
|
||||||
lineNudges = fromMaybe 0 . flip Map.lookup eaocNudge
|
lineNudges = fromMaybe 0 . flip Map.lookup eaocNudge
|
||||||
|
|
||||||
bestOption :: Maybe [(ExamOccurrenceId, [[CI Char]])]
|
bestOption :: Either ExamAutoOccurrenceException [(ExamOccurrenceId, [[CI Char]])]
|
||||||
bestOption = case rule of
|
bestOption = case rule of
|
||||||
ExamRoomSurname -> do
|
ExamRoomSurname -> maybeToRight ExamAutoOccurrenceExceptionRoomTooSmall $ do
|
||||||
(_cost, res) <- distribute (sortBy (RFC5051.compareUnicode `on` (pack . toListOf (_1 . folded . to CI.foldedCase))) . Map.toAscList $ fromIntegral . Set.size <$> users') occurrences'' lineNudges charCost
|
(_cost, res) <- distribute (sortBy (RFC5051.compareUnicode `on` (pack . toListOf (_1 . folded . to CI.foldedCase))) . Map.toAscList $ fromIntegral . Set.size <$> users') occurrences'' lineNudges charCost
|
||||||
-- traceM $ show cost
|
-- traceM $ show cost
|
||||||
return res
|
return res
|
||||||
ExamRoomMatriculation -> do
|
ExamRoomMatriculation -> maybeToRight ExamAutoOccurrenceExceptionRoomTooSmall $ do
|
||||||
let usersFineness n = Map.toAscList $ fromIntegral . Set.size <$> Map.mapKeysWith Set.union (reverse . take (fromIntegral n) . reverse) users'
|
let usersFineness n = Map.toAscList $ fromIntegral . Set.size <$> Map.mapKeysWith Set.union (reverse . take (fromIntegral n) . reverse) users'
|
||||||
-- finenessCost n = Finite (max 1 $ fromIntegral n * eaocFinenessCost * fromIntegral longestLine) ^ 2 * length occurrences'
|
-- finenessCost n = Finite (max 1 $ fromIntegral n * eaocFinenessCost * fromIntegral longestLine) ^ 2 * length occurrences'
|
||||||
|
|
||||||
@ -556,7 +567,7 @@ examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences
|
|||||||
|
|
||||||
(_cost, res) <- fmap (minimumBy . comparing $ view _1) . fromNullable $ genResults 1
|
(_cost, res) <- fmap (minimumBy . comparing $ view _1) . fromNullable $ genResults 1
|
||||||
return res
|
return res
|
||||||
_other -> Nothing
|
_other -> Left ExamAutoOccurrenceExceptionRuleNoOp
|
||||||
|
|
||||||
postprocess :: [(ExamOccurrenceId, [[CI Char]])]
|
postprocess :: [(ExamOccurrenceId, [[CI Char]])]
|
||||||
-> ( Map ExamOccurrenceId (Set ExamOccurrenceMappingDescription)
|
-> ( Map ExamOccurrenceId (Set ExamOccurrenceMappingDescription)
|
||||||
@ -690,6 +701,7 @@ examAutoOccurrence (hash -> seed) rule ExamAutoOccurrenceConfig{..} occurrences
|
|||||||
checkSpecial = case rule of
|
checkSpecial = case rule of
|
||||||
ExamRoomMatriculation -> isSuffixOf
|
ExamRoomMatriculation -> isSuffixOf
|
||||||
_rule -> isPrefixOf
|
_rule -> isPrefixOf
|
||||||
|
ExamOccurrenceMappingRandom -> False -- Something went wrong, throw an error instead?
|
||||||
|
|
||||||
resultUsers :: Map UserId (Maybe ExamOccurrenceId)
|
resultUsers :: Map UserId (Maybe ExamOccurrenceId)
|
||||||
resultUsers = Map.fromList $ do
|
resultUsers = Map.fromList $ do
|
||||||
|
|||||||
@ -191,6 +191,7 @@ examOccurrenceRuleAutomatic x = any ($ x)
|
|||||||
data ExamOccurrenceMappingDescription
|
data ExamOccurrenceMappingDescription
|
||||||
= ExamOccurrenceMappingRange { eaomrStart, eaomrEnd :: [CI Char] }
|
= ExamOccurrenceMappingRange { eaomrStart, eaomrEnd :: [CI Char] }
|
||||||
| ExamOccurrenceMappingSpecial { eaomrSpecial :: [CI Char] }
|
| ExamOccurrenceMappingSpecial { eaomrSpecial :: [CI Char] }
|
||||||
|
| ExamOccurrenceMappingRandom
|
||||||
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
deriveJSON defaultOptions
|
deriveJSON defaultOptions
|
||||||
{ fieldLabelModifier = camelToPathPiece' 1
|
{ fieldLabelModifier = camelToPathPiece' 1
|
||||||
|
|||||||
@ -13,3 +13,5 @@ $newline never
|
|||||||
#{titleCase special}…
|
#{titleCase special}…
|
||||||
$else
|
$else
|
||||||
…#{titleCase special}
|
…#{titleCase special}
|
||||||
|
$of ExamOccurrenceMappingRandom
|
||||||
|
Random
|
||||||
|
|||||||
@ -14,6 +14,9 @@ $newline never
|
|||||||
$of ExamRoomMatriculation
|
$of ExamRoomMatriculation
|
||||||
<th .table__th>
|
<th .table__th>
|
||||||
_{MsgExamRoomMappingMatriculation}
|
_{MsgExamRoomMappingMatriculation}
|
||||||
|
$of ExamRoomRandom
|
||||||
|
<th .table__th>
|
||||||
|
_{MsgExamRoomMappingRandom}
|
||||||
$of _
|
$of _
|
||||||
<th .table__td>
|
<th .table__td>
|
||||||
<th .table__th>
|
<th .table__th>
|
||||||
|
|||||||
Reference in New Issue
Block a user