Skip to content

Add configurable action repetition for SelectAS tasks with maximized distance, length bounds filtering, and randomized wrong sequence selection#433

Merged
marcellussiegburg merged 97 commits intodevfrom
copilot/add-action-repetition-configuration
Oct 27, 2025
Merged

Add configurable action repetition for SelectAS tasks with maximized distance, length bounds filtering, and randomized wrong sequence selection#433
marcellussiegburg merged 97 commits intodevfrom
copilot/add-action-repetition-configuration

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 14, 2025

Addressing @jvoigtlaender comment 3446987175:

Fixed the pattern matching in computeActionSequenceLevels to use proper "deeper pattern-matching":

Instead of nested case expressions:

case k of
  NormalPetriNode {} -> case sourceNode k of
    AdActionNode {name = actionName} -> ...

Now using tuple pattern matching to match both patterns simultaneously:

case (k, sourceNode k) of
  (NormalPetriNode {}, AdActionNode {name = actionName}) -> ...

This is more idiomatic Haskell and avoids the nested structure. Build succeeds and hlint shows no hints.

Original prompt

This section details on the original issue you should resolve

<issue_title>Aktionswiederholung bei AD-Sequenzauswahl</issue_title>
<issue_description>Es scheint so als würden niemals Sequenzen angeboten, in denen eine Aktion mehrmals auftritt.

Siehe zum Beispiel https://autotool.fmi.uni-due.de/route/aufgabe/417 (eine SelectAS-Aufgabe), wo cycles = 1 gesetzt ist, also immer die Möglichkeit einer Wiederholung bestünde (sofern der Zyklus mindestens einen Aktionsknoten enthält), aber scheinbar immer nur Listen erzeugt werden, in denen sich nichts wiederholt.

Die Aufgaben könnten etwas interessanter gestaltet werden, wenn zum Beispiel über eine Konfigurationsoption eingestellt werden könnte, ob/dass es mindestens eine Aktionsdopplung geben soll.

</issue_description>

<agent_instructions>The failed #411 tried to do it like this (when "generate sequences with repetation" was configured):

  1. generate a correct action sequence
  2. randomly put additional actions into it and check whether the result happens to still be a correct action sequence
  3. for the intended wrong sequences, instead of only permuting the correct one, also put random stuff into them and check whether the result happens to be a wrong action sequence

This naive generate-and-test approach was doomed.

Instead, this approach should be used (under the appropriately introduced configuration option):

  • generate a correct action sequence that happens to include repetition (that simply means to not immediately take the first hit of levels' in generateActionSequence') -- instead of 1. and 2. steps above
  • fot the intended wrong sequences, only permute the currect one and filter for incorrect ones -- exactly what the current code is already doing in the absence of configured repetitions</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@jvoigtlaender The failed #411 tried to do it like this (when "generate sequences with repetation" was configured): 1. generate a correct action sequence 2. randomly put additional actions into it and check whether the result happens to still be a correct action sequence 3. for the intended wrong sequences, instead of only permuting the correct one, also put random stuff into them and check whether the result happens to be a wrong action sequence

This naive generate-and-test approach was doomed.

Instead, this approach should be used (under the appropriately introduced configuration option):

  • generate a correct action sequence that happens to include repetition (that simply means to not immediately take the first hit of levels' in generateActionSequence') -- instead of 1. and 2. steps above
  • fot the intended wrong sequences, only permute the currect one and filter for incorrect ones -- exactly what the current code is already doing in the absence of configured repetitions</comment_new>

Fixes #230


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits October 14, 2025 09:44
Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copilot AI changed the title [WIP] Add configuration for action repetition in sequence generation Add configuration option for action repetition in SelectAS tasks Oct 14, 2025
Copilot AI requested a review from jvoigtlaender October 14, 2025 10:10
@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot:

I want the new configuration option to not just "allow" repetition, but indeed try its utmost best to actually introduce repetition. It should reall try to make it happen unless it is not doable at all.

In that context, the constraints imposed by checkSelectASInstanceForConfig also need to be respected and factored in.

Moreover, checkSelectASConfig' should ensure that the new options isn't turned on when there aren't actually going to be cycles in the AD.

And maybe it is possible to turn the Bool config parameter into something numeric, that steers how long the subsequence is (at least) until an action is repeated? (That is, == 0 would mean the sequence gets a [..., A, A, ...], whereas == 1 would mean to expect something like [..., A, B, A, ...] etc.)

And the test suite should contain some explicit test that setting the new config parameter to positive indeed leads to repetition.

…dation and tests

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 14, 2025

@copilot:

I want the new configuration option to not just "allow" repetition, but indeed try its utmost best to actually introduce repetition. It should reall try to make it happen unless it is not...

I've made the requested changes in commit 4d97cac:

  1. Changed from Bool to Int parameter: The configuration option is now minActionRepetitionDistance :: Int where:

    • -1 = no repetition (default, backward compatible)
    • 0 = immediate repetition like [A, A, ...]
    • 1 = at least one action between like [A, B, A, ...]
    • 2+ = correspondingly more actions between repetitions
  2. Added validation in checkSelectASConfig':

    • Rejects minActionRepetitionDistance < -1
    • Requires cycles >= 1 when minActionRepetitionDistance >= 0
  3. Improved sequence generation: The implementation now actively searches through all available paths to the zero state and selects one that satisfies the minimum repetition distance requirement. If no sequence with the exact requirement exists, it takes the longest available path as a best effort.

  4. Added comprehensive tests in SelectASSpec.hs:

    • Tests validation for the new parameter
    • Tests that minDistance = 0 produces immediate repetition
    • Tests that minDistance = 1 produces repetition with at least 1 action between
  5. Exported helper function hasActionRepetitionWithMinDistance for checking if sequences meet the requirement.

The implementation now tries its utmost best to achieve repetition when configured, only falling back to longer paths without exact matches when the diagram structure doesn't allow the specific repetition pattern.

Copilot AI changed the title Add configuration option for action repetition in SelectAS tasks Add configurable action repetition distance for SelectAS tasks Oct 14, 2025
@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot:

Instead of Int with "magic number" -1, use Maybe Int.

If hasActionRepetitionWithMinDistance is only used in a test module, it should be moved there.

…t helper

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 14, 2025

@copilot:

Instead of Int with "magic number" -1, use Maybe Int.
...

Done in commit (will be pushed shortly):

  1. Changed minActionRepetitionDistance from Int with magic number -1 to Maybe Int:

    • Nothing = no repetition (default)
    • Just 0 = immediate repetition
    • Just 1 = at least 1 action between repetitions
    • Just n = at least n actions between
  2. Moved hasActionRepetitionWithMinDistance from ActionSequences module to SelectASSpec test module since it's only used there.

Updated all function signatures, validation logic, and test cases accordingly.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot:

Don't implement your own nub functions.

The relevant configurations in the example subdirectory also all need to be updated.

Is the "otherwise take the longest as best effort" really a good idea when actually checkSelectASInstanceForConfig may have to winnow these out then?

…llback logic

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 14, 2025

@copilot:

Don't implement your own nub functions.
...

Done in commit (will be pushed shortly):

  1. Replaced custom nub implementations with Data.List.nub in both source and test modules.

  2. Updated example configurations (example/src/Modelling/ActivityDiagram/SelectAs/Config.hs) to include minActionRepetitionDistance = Nothing for all tasks.

  3. Changed the fallback logic: when the repetition requirement can't be met, now returns the shortest sequence instead of the longest. This avoids potential violations of answerLength constraints in checkSelectASInstanceForConfig, as shorter sequences are less likely to exceed the maximum length limit.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, change your local variable names to respect the naming guidelines from .github/copilot-instructions.md.

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 14, 2025

@copilot, change your local variable names to respect the naming guidelines from .github/copilot-instructions.md.

Done in commit (will be pushed shortly). Renamed all abbreviated local variables to follow naming guidelines:

  • tSeqtransitionSequence
  • lbllabelValue
  • bestSeqbestSequence
  • adactivityDiagram

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, in selectActionSequence actually not all groups for the wrong sequences need to be shuffled but only the last needed group. The others can be passed to the concat without preceding shuffle.

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 24, 2025

@copilot, in selectActionSequence actually not all groups for the wrong sequences need to be shuffled but only the last needed group. The others can be passed to the concat without preceding shuff...

Done in commit c7f28b9. Now only the last needed group is shuffled, while full groups that we take entirely are passed through without shuffling.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, have a go at this:

  let petriKeyMap = map
        (\k -> (Ad.label $ sourceNode k, k))
        $ filter isNormalPetriNode $ M.keys $ allNodes petri
      input' = mapMaybe (`lookup` petriKeyMap) (mapMaybe (`BM.lookupR` actionLookup) input)
      actions = map snd $ filter (\(l,_) -> l `BM.member` actionLookup) petriKeyMap

in src/Modelling/ActivityDiagram/ActionSequences.hs should be simplified, given that we know the actionLookup was produced by

extractActionLookup :: UMLActivityDiagram -> BM.Bimap Int String
extractActionLookup diag = BM.fromList
  [ (Ad.label n, name n)
  | n <- nodes diag
  , isActionNode n
  ]

from the diag corresponding to the petri here (so the information all exists locally already).

…om sourceNode

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 25, 2025

@copilot, have a go at this:

...

Done in commit d501f20. The function now extracts action information directly from sourceNode by pattern matching on AdActionNode, eliminating the redundant lookup through actionLookup. The actionLookup parameter is now unused and marked with an underscore.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, it's your responsibility that the build actually works (including the test suite) after you have made a change.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, it's your responsibility that the build actually works (including the test suite) after you have made a change. Generally, make sure to follow the guidelines from .github/copilot-instructions.md.

Also, if the actionLookup parameter is not needed anymore, then it should be removed from the function completely, and also from all call sites.

If possible, the extractActionLookup function should then also be removed completely.

…ion completely

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 25, 2025

@copilot, it's your responsibility that the build actually works (including the test suite) after you have made a change. Generally, make sure to follow the guidelines from `.github/copilot-instructio...

Fixed in commit 4323b20. Removed the unused actionLookup parameter from all functions, removed the extractActionLookup function completely, and cleaned up all imports including Data.Bimap. Build succeeds with stack test --no-run-tests.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, in computeActionSequenceLevels integrate the filter into the relevant mapMaybe.

Also, make sure the code passes hlint linting.

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 25, 2025

@copilot, in computeActionSequenceLevels integrate the filter into the relevant mapMaybe.

Also, make sure the code passes hlint linting.

Done in commit 082a53f. Integrated the filter into mapMaybe in computeActionSequenceLevels, and fixed the hlint suggestion in SelectAS.hs by using the infix section. Code now passes hlint with no hints.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, obviously I wanted you to not use if isNormalPetriNode but instead use deeper pattern-matching.

If after that refactoring the function isNormalPetriNode is not anymore needed anywhere, drop it from the code completely.

… unused isNormalPetriNode function

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 25, 2025

@copilot, obviously I wanted you to not use if isNormalPetriNode but instead use deeper pattern-matching.

If after that refactoring the function isNormalPetriNode is not anymore needed anywhere...

Fixed in commit 39f84bc. Replaced if isNormalPetriNode with nested pattern matching on NormalPetriNode {} and removed the unused isNormalPetriNode function completely.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, that's not what I meant by "deeper pattern-matching". Try to do better.

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 25, 2025

@copilot, that's not what I meant by "deeper pattern-matching". Try to do better.

Fixed in commit 440a34d by using tuple pattern matching case (k, sourceNode k) of to match both NormalPetriNode {} and AdActionNode {name = actionName} simultaneously, eliminating the nested case expression.

@jvoigtlaender
Copy link
Copy Markdown
Member

@marcellussiegburg, can you check whether d501f20 is semantically correct? Everything after that is just refactorings and should be fine.

@marcellussiegburg
Copy link
Copy Markdown
Member

@marcellussiegburg, can you check whether d501f20 is semantically correct? Everything after that is just refactorings and should be fine.

Yes. That is correct.

@jvoigtlaender
Copy link
Copy Markdown
Member

Okay, then I think the only open point before merging this PR is my slight uncertainty concerning the use (types) of randomness expressed further above:

Maybe you additionally want to take a look at the randomness introduced into generateActionSequenceWithPetriAndRepetition and selectActionSequence. In particular, I cannot really say whether it is the best approach to express the randomness differently in those two cases, once with MonadRandom and once with RandT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aktionswiederholung bei AD-Sequenzauswahl

4 participants