Skip to content

Fix Dijkstra predecessor tracking, complement edge removal, and banana tree positioning#83

Merged
rostam merged 1 commit intomasterfrom
copilot/solve-existing-issues
Mar 25, 2026
Merged

Fix Dijkstra predecessor tracking, complement edge removal, and banana tree positioning#83
rostam merged 1 commit intomasterfrom
copilot/solve-existing-issues

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 25, 2026

Addresses three long-standing bugs reported in issues #53/#70, #48, and #15.

Dijkstra shortest path returns wrong results (#53, #70)

prev.set(edge.source.getId(), edge.target) uses the edge's stored source/target fields, which don't correspond to traversal direction in undirected graphs. Changed to standard predecessor tracking:

// Before: uses edge endpoints (wrong for undirected graphs)
prev.set(edge.source.getId(), edge.target);

// After: tracks actual predecessor in shortest path tree
prev.set(target.getId(), vMin);

Tests updated from (incorrect) successor semantics to predecessor semantics, consistent with how Johnson.java already consumes the result.

Complement selection doesn't delete existing edges (#48)

Two bugs in MakeSelectionComplementGraph.doEdgeOperation():

  • Missing reverse removal: ListGraph.removeAllEdges(source, target) only removes the source→target direction. For undirected graphs, the reverse must also be removed.
  • Self-loop injection: Pairs where v1 == v2 were not skipped, so complement incorrectly added self-loops.

Banana tree leaf positioning broken when k ≠ n (#15)

The skip condition determining which leaf position overlaps the root edge used (i + k/2) % n — modulo n (star count) instead of k (leaf count), and didn't scale the star index. Fixed to (i * k / n + k / 2) % k which correctly identifies the leaf position pointing toward root for each star.

…, banana tree positioning (#15)

- Dijkstra: Fix prev.set(edge.source.getId(), edge.target) → prev.set(target.getId(), vMin)
  to correctly track predecessors in shortest path tree
- Complement: Skip self-loops, remove undirected edges in both directions
  since removeAllEdges only removes source→target direction
- BananaTree: Fix skip condition (i+k/2)%n → (i*k/n+k/2)%k to correctly
  calculate which leaf position points toward root

Co-authored-by: rostam <1497363+rostam@users.noreply.github.com>
Agent-Logs-Url: https://github.com/rostam/GraphTea/sessions/3b924362-279a-41f3-9237-c722508d2703
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix Dijkstra, complement graph, and banana tree bugs

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Fix Dijkstra predecessor tracking in shortest path tree
  - Changed prev.set(edge.source.getId(), edge.target) to prev.set(target.getId(), vMin)
  - Correctly tracks predecessors instead of edge endpoints for undirected graphs
• Fix complement graph edge removal for undirected graphs
  - Skip self-loops when processing vertex pairs
  - Remove edges in both directions since removeAllEdges only removes source→target
• Fix banana tree leaf positioning calculation
  - Changed skip condition from (i + k/2) % n to (i * k / n + k / 2) % k
  - Correctly identifies leaf position pointing toward root for each star
• Update Dijkstra tests to verify predecessor semantics
  - Changed assertions from successor to predecessor chain validation
  - Added null checks and descriptive assertion messages
Diagram
flowchart LR
  A["Dijkstra Algorithm"] -->|Fix predecessor tracking| B["Correct shortest path tree"]
  C["Complement Graph"] -->|Skip self-loops & remove both directions| D["Correct edge removal"]
  E["Banana Tree Generator"] -->|Fix leaf position formula| F["Correct positioning"]
  B -->|Update tests| G["Predecessor semantics validation"]
Loading

Grey Divider

File Changes

1. src/graphtea/extensions/algorithms/shortestpath/algs/Dijkstra.java 🐞 Bug fix +1/-1

Fix Dijkstra predecessor tracking

• Fixed predecessor tracking in shortest path tree calculation
• Changed from using edge endpoints to tracking actual predecessor vertex
• Corrects behavior for undirected graphs where edge.source/target don't reflect traversal direction

src/graphtea/extensions/algorithms/shortestpath/algs/Dijkstra.java


2. src/graphtea/extensions/generators/BananaTreeGenerator.java 🐞 Bug fix +1/-1

Fix banana tree leaf positioning formula

• Fixed leaf position skip condition calculation
• Changed from (i + k/2) % n to (i * k / n + k / 2) % k
• Correctly identifies which leaf position overlaps root edge when k ≠ n

src/graphtea/extensions/generators/BananaTreeGenerator.java


3. src/graphtea/plugins/main/select/MakeSelectionComplementGraph.java 🐞 Bug fix +10/-4

Fix complement graph edge removal

• Added self-loop skip condition to prevent complement from adding self-loops
• Added reverse edge removal for undirected graphs
• Ensures both directions are removed since removeAllEdges only removes source→target
• Improved code formatting and readability

src/graphtea/plugins/main/select/MakeSelectionComplementGraph.java


View more (1)
4. test/AlgorithmsTest.java 🧪 Tests +12/-8

Update Dijkstra tests to predecessor semantics

• Updated test documentation from successor to predecessor semantics
• Changed assertions to verify predecessor chain instead of successor chain
• Added null check for source vertex and descriptive assertion messages
• Updated both testDijkstraLinearPath and testDijkstraDiamond tests

test/AlgorithmsTest.java


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Mar 25, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (1) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. if without braces 📘 Rule violation ⚙ Maintainability
Description
The modified if statement uses a single-line body without braces, which violates the NeedBraces
requirement and increases risk of future control-flow mistakes during edits.
Code

src/graphtea/extensions/generators/BananaTreeGenerator.java[79]

+                if (j == (i * k / n + k / 2) % k) continue;
Evidence
PR Compliance ID 6 requires braces for all if/for/while bodies in new/modified code. The line
shown uses if (...) continue; without braces.

CLAUDE.md
src/graphtea/extensions/generators/BananaTreeGenerator.java[79-79]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A modified `if` statement omits braces (NeedBraces violation).

## Issue Context
Single-line control statements without braces are disallowed by the compliance checklist and can lead to accidental logic changes when additional lines are added later.

## Fix Focus Areas
- src/graphtea/extensions/generators/BananaTreeGenerator.java[79-79]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Directed edges traversed backwards 🐞 Bug ✓ Correctness
Description
Dijkstra.getShortestPath() iterates *all incident edges* via graph.edgeIterator(vMin) and then
picks the “other endpoint”, which causes incoming edges in directed graphs to be relaxed in reverse
direction and can produce paths that do not exist in the directed graph.
Code

src/graphtea/extensions/algorithms/shortestpath/algs/Dijkstra.java[100]

+                        prev.set(target.getId(), vMin);
Evidence
In algs/Dijkstra, the neighbor is computed as vMin == edge.source ? edge.target : edge.source
while iterating graph.edgeIterator(vMin), so an edge u -> vMin (incoming) will be treated as
traversable from vMin to u. This is possible because ListGraph.edgeIterator(VertexType v)
explicitly includes both outgoing edges (from list) and incoming edges (from inverseList) when
the graph is directed; therefore the algorithm will see edges where vMin is the *target* and will
reverse them during relaxation. Since Johnson calls this Dijkstra (dj.getShortestPath(g, v)),
Johnson’s computed paths can also be invalid on directed graphs.

src/graphtea/extensions/algorithms/shortestpath/algs/Dijkstra.java[84-101]
src/graphtea/library/ListGraph.java[220-244]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`algs/Dijkstra#getShortestPath` currently traverses directed graphs as undirected by iterating all incident edges (`edgeIterator(vMin)`) and selecting the opposite endpoint, which can relax incoming edges backwards.

### Issue Context
`ListGraph.edgeIterator(v)` for directed graphs returns both outgoing and incoming edges, so Dijkstra must explicitly restrict traversal to outgoing edges (or filter by `edge.source == vMin`) when `graph.isDirected()`.

### Fix Focus Areas
- src/graphtea/extensions/algorithms/shortestpath/algs/Dijkstra.java[84-103]
- src/graphtea/library/ListGraph.java[220-244]

### Implementation notes
- Prefer `graph.edgeIterator(vMin, true)` (source/outgoing) for directed graphs and use `target = edge.target`.
- Keep the current undirected behavior for `!graph.isDirected()` (incident edges + opposite endpoint).
- Ensure `prev.set(target.getId(), vMin)` is only applied for valid traversal direction in directed graphs.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@rostam rostam merged commit e6277e1 into master Mar 25, 2026
3 checks passed
GPoint[] sR = PositionGenerators.circle(1000, center.x, center.y, k);
for (int j = 0; j < k; j++) {
if(j == (i + k/2)%n) continue;
if (j == (i * k / n + k / 2) % k) continue;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. if without braces 📘 Rule violation ⚙ Maintainability

The modified if statement uses a single-line body without braces, which violates the NeedBraces
requirement and increases risk of future control-flow mistakes during edits.
Agent Prompt
## Issue description
A modified `if` statement omits braces (NeedBraces violation).

## Issue Context
Single-line control statements without braces are disallowed by the compliance checklist and can lead to accidental logic changes when additional lines are added later.

## Fix Focus Areas
- src/graphtea/extensions/generators/BananaTreeGenerator.java[79-79]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

target.setColor(5);
Q.add(target);
prev.set(edge.source.getId(), edge.target);
prev.set(target.getId(), vMin);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Directed edges traversed backwards 🐞 Bug ✓ Correctness

Dijkstra.getShortestPath() iterates *all incident edges* via graph.edgeIterator(vMin) and then
picks the “other endpoint”, which causes incoming edges in directed graphs to be relaxed in reverse
direction and can produce paths that do not exist in the directed graph.
Agent Prompt
### Issue description
`algs/Dijkstra#getShortestPath` currently traverses directed graphs as undirected by iterating all incident edges (`edgeIterator(vMin)`) and selecting the opposite endpoint, which can relax incoming edges backwards.

### Issue Context
`ListGraph.edgeIterator(v)` for directed graphs returns both outgoing and incoming edges, so Dijkstra must explicitly restrict traversal to outgoing edges (or filter by `edge.source == vMin`) when `graph.isDirected()`.

### Fix Focus Areas
- src/graphtea/extensions/algorithms/shortestpath/algs/Dijkstra.java[84-103]
- src/graphtea/library/ListGraph.java[220-244]

### Implementation notes
- Prefer `graph.edgeIterator(vMin, true)` (source/outgoing) for directed graphs and use `target = edge.target`.
- Keep the current undirected behavior for `!graph.isDirected()` (incident edges + opposite endpoint).
- Ensure `prev.set(target.getId(), vMin)` is only applied for valid traversal direction in directed graphs.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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.

2 participants