ConceptGraphService.java

1
package edu.ucsb.cs.scaffold.services;
2
3
import edu.ucsb.cs.scaffold.entity.Concept;
4
import edu.ucsb.cs.scaffold.entity.ConceptEdge;
5
import java.util.ArrayDeque;
6
import java.util.ArrayList;
7
import java.util.Comparator;
8
import java.util.Deque;
9
import java.util.HashMap;
10
import java.util.HashSet;
11
import java.util.List;
12
import java.util.Map;
13
import java.util.Set;
14
import java.util.stream.Collectors;
15
import org.springframework.stereotype.Service;
16
17
/**
18
 * Graph algorithms for the prerequisite structure of a course's top-level concepts (subconcepts
19
 * have no position in this graph). Prerequisite edges only ever connect top-level concepts, so
20
 * every method here operates on that subgraph.
21
 *
22
 * <p>{@link #reset} is the analysis run by {@code POST /api/course/scaffold/reset}: it detects
23
 * cycles (flagging their edges rather than processing them further), removes edges that are
24
 * redundant given the graph's transitive structure, ranks concepts by longest path from a root, and
25
 * lays out each level's x,y position. It is a pure function of its inputs — no repository access —
26
 * so the controller owns loading input and persisting the result.
27
 */
28
@Service
29
public class ConceptGraphService {
30
31
  // Index i holds the color for level i+1; levels beyond the palette reuse the last color.
32
  public static final List<String> LEVEL_COLORS =
33
      List.of("#c99ffe", "#feaef2", "#93ebff", "#fe9a71", "#2bcd9c");
34
35
  public static final String CYCLE_EDGE_COLOR = "#FF0000";
36
37
  // Initial guesses; revisit if the resulting layout looks too cramped or too sparse.
38
  public static final int MIN_HORIZONTAL_SEPARATION = 350;
39
  public static final int VERTICAL_LEVEL_SEPARATION = 300;
40
41
  /** The color assigned to a top-level concept at the given longest-path level (1-based). */
42
  public String colorForLevel(int level) {
43 1 1. colorForLevel : Replaced integer subtraction with addition → KILLED
    int index = Math.min(Math.max(level, 1), LEVEL_COLORS.size()) - 1;
44 1 1. colorForLevel : replaced return value with "" for edu/ucsb/cs/scaffold/services/ConceptGraphService::colorForLevel → KILLED
    return LEVEL_COLORS.get(index);
45
  }
46
47
  /**
48
   * True if adding an edge sourceId -&gt; targetId would create a cycle, i.e. targetId can already
49
   * reach sourceId via existingEdges. Used to reject new prerequisite edges at creation time,
50
   * before a cycle can ever be persisted.
51
   */
52
  public boolean wouldCreateCycle(List<ConceptEdge> existingEdges, Long sourceId, Long targetId) {
53
    Map<Long, List<Long>> adjacency = buildAdjacency(existingEdges);
54
    Set<Long> visited = new HashSet<>();
55
    Deque<Long> queue = new ArrayDeque<>();
56
    visited.add(targetId);
57
    queue.add(targetId);
58 1 1. wouldCreateCycle : negated conditional → KILLED
    while (!queue.isEmpty()) {
59
      Long current = queue.poll();
60 1 1. wouldCreateCycle : negated conditional → KILLED
      if (current.equals(sourceId)) {
61 1 1. wouldCreateCycle : replaced boolean return with false for edu/ucsb/cs/scaffold/services/ConceptGraphService::wouldCreateCycle → KILLED
        return true;
62
      }
63
      for (Long next : adjacency.getOrDefault(current, List.of())) {
64 1 1. wouldCreateCycle : negated conditional → KILLED
        if (visited.add(next)) {
65
          queue.add(next);
66
        }
67
      }
68
    }
69 1 1. wouldCreateCycle : replaced boolean return with true for edu/ucsb/cs/scaffold/services/ConceptGraphService::wouldCreateCycle → KILLED
    return false;
70
  }
71
72
  public record Position(int x, int y) {}
73
74
  public record ResetResult(
75
      Set<Long> cycleEdgeIds,
76
      Set<Long> removedEdgeIds,
77
      Map<Long, Integer> levelByConceptId,
78
      Map<Long, Position> positionByConceptId) {}
79
80
  /**
81
   * Runs the full scaffold reset analysis: cycle detection, transitive reduction, longest-path
82
   * leveling, and layout. Does not mutate concepts or edges or read/write any repository; the
83
   * caller applies {@link ResetResult} to persistent entities.
84
   *
85
   * @param topLevelConcepts every top-level concept in the course (used for their id/x, to sort and
86
   *     lay out concepts with no edges at all, and as the node set for the graph algorithms)
87
   * @param edges every prerequisite edge in the course
88
   */
89
  public ResetResult reset(List<Concept> topLevelConcepts, List<ConceptEdge> edges) {
90
    Map<Long, Integer> priorXByConceptId =
91
        topLevelConcepts.stream().collect(Collectors.toMap(Concept::getId, Concept::getX));
92 1 1. reset : replaced return value with null for edu/ucsb/cs/scaffold/services/ConceptGraphService::reset → KILLED
    return reset(topLevelConcepts, edges, priorXByConceptId);
93
  }
94
95
  /**
96
   * Like {@link #reset(List, List)}, but sorts each level by the given prior x values instead of
97
   * each concept's own x column. Used by the controller to sort by the requesting user's private,
98
   * unsaved drag positions where they exist, falling back to the concept's persisted x otherwise —
99
   * see {@code POST /api/course/scaffold/reset}.
100
   */
101
  public ResetResult reset(
102
      List<Concept> topLevelConcepts,
103
      List<ConceptEdge> edges,
104
      Map<Long, Integer> priorXByConceptId) {
105
    Set<Long> nodeIds = topLevelConcepts.stream().map(Concept::getId).collect(Collectors.toSet());
106
107
    Map<Long, Long> sccId = computeStronglyConnectedComponents(buildAdjacency(edges), nodeIds);
108
    Map<Long, Long> sccSize =
109 1 1. lambda$reset$0 : replaced Long return value with 0L for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$reset$0 → KILLED
        sccId.values().stream().collect(Collectors.groupingBy(id -> id, Collectors.counting()));
110
111
    Set<Long> cycleEdgeIds = new HashSet<>();
112
    List<ConceptEdge> acyclicEdges = new ArrayList<>();
113
    for (ConceptEdge edge : edges) {
114
      Long sourceId = edge.getSource().getId();
115
      Long targetId = edge.getTarget().getId();
116
      boolean inCycle =
117 3 1. reset : negated conditional → KILLED
2. reset : changed conditional boundary → KILLED
3. reset : negated conditional → KILLED
          sccId.get(sourceId).equals(sccId.get(targetId)) && sccSize.get(sccId.get(sourceId)) > 1;
118 1 1. reset : negated conditional → KILLED
      if (inCycle) {
119
        cycleEdgeIds.add(edge.getId());
120
      } else {
121
        acyclicEdges.add(edge);
122
      }
123
    }
124
125
    Set<Long> removedEdgeIds = computeTransitiveReductionRemovals(nodeIds, acyclicEdges);
126
127
    // The transitively redundant edges are only reported for deletion, not filtered out
128
    // before leveling: a removed edge u->v is by definition a shortcut for a longer path
129
    // u -> ... -> v, whose constraint on v's level always dominates, so including or
130
    // excluding these edges cannot change any longest-path level.
131
    Map<Long, Integer> levelByConceptId = computeLongestPathLevels(nodeIds, acyclicEdges);
132
    Map<Long, Position> positionByConceptId =
133
        computeLayout(topLevelConcepts, levelByConceptId, priorXByConceptId);
134
135 1 1. reset : replaced return value with null for edu/ucsb/cs/scaffold/services/ConceptGraphService::reset → KILLED
    return new ResetResult(cycleEdgeIds, removedEdgeIds, levelByConceptId, positionByConceptId);
136
  }
137
138
  /**
139
   * Lays each level out left to right, sorted by each concept's prior x (then id to break ties),
140
   * centered horizontally at x=0. Each level sits {@link #VERTICAL_LEVEL_SEPARATION} above the
141
   * previous one, with level 1 at y=0.
142
   */
143
  private Map<Long, Position> computeLayout(
144
      List<Concept> topLevelConcepts,
145
      Map<Long, Integer> levelByConceptId,
146
      Map<Long, Integer> priorXByConceptId) {
147
    Map<Integer, List<Concept>> byLevel =
148
        topLevelConcepts.stream()
149 1 1. lambda$computeLayout$1 : replaced Integer return value with 0 for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$computeLayout$1 → KILLED
            .collect(Collectors.groupingBy(c -> levelByConceptId.get(c.getId())));
150
151
    Map<Long, Position> positions = new HashMap<>();
152
    for (Map.Entry<Integer, List<Concept>> entry : byLevel.entrySet()) {
153
      int level = entry.getKey();
154
      List<Concept> sorted =
155
          entry.getValue().stream()
156
              .sorted(
157 1 1. lambda$computeLayout$2 : replaced Integer return value with 0 for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$computeLayout$2 → KILLED
                  Comparator.comparing((Concept c) -> priorXByConceptId.get(c.getId()))
158
                      .thenComparing(Concept::getId))
159
              .toList();
160
      int n = sorted.size();
161 3 1. computeLayout : Replaced integer subtraction with addition → KILLED
2. computeLayout : removed negation → KILLED
3. computeLayout : Replaced integer multiplication with division → KILLED
      int y = -(level - 1) * VERTICAL_LEVEL_SEPARATION;
162 2 1. computeLayout : changed conditional boundary → KILLED
2. computeLayout : negated conditional → KILLED
      for (int i = 0; i < n; i++) {
163 4 1. computeLayout : Replaced double multiplication with division → KILLED
2. computeLayout : Replaced integer subtraction with addition → KILLED
3. computeLayout : Replaced double subtraction with addition → KILLED
4. computeLayout : Replaced double division with multiplication → KILLED
        int x = (int) Math.round((i - (n - 1) / 2.0) * MIN_HORIZONTAL_SEPARATION);
164
        positions.put(sorted.get(i).getId(), new Position(x, y));
165
      }
166
    }
167 1 1. computeLayout : replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeLayout → KILLED
    return positions;
168
  }
169
170
  /**
171
   * Tarjan's algorithm: maps each node id to an id shared by its strongly connected component (a
172
   * nontrivial cycle iff more than one node shares it). The component id is the id of the
173
   * component's root node — any value unique per component would do, and using the root avoids
174
   * maintaining a separate counter.
175
   */
176
  private Map<Long, Long> computeStronglyConnectedComponents(
177
      Map<Long, List<Long>> adjacency, Set<Long> nodeIds) {
178
    TarjanState state = new TarjanState(adjacency);
179
    for (Long node : nodeIds) {
180 1 1. computeStronglyConnectedComponents : negated conditional → KILLED
      if (!state.index.containsKey(node)) {
181 1 1. computeStronglyConnectedComponents : removed call to edu/ucsb/cs/scaffold/services/ConceptGraphService$TarjanState::strongConnect → KILLED
        state.strongConnect(node);
182
      }
183
    }
184 1 1. computeStronglyConnectedComponents : replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeStronglyConnectedComponents → KILLED
    return state.sccId;
185
  }
186
187
  private static final class TarjanState {
188
    private final Map<Long, List<Long>> adjacency;
189
    private final Map<Long, Integer> index = new HashMap<>();
190
    private final Map<Long, Integer> lowlink = new HashMap<>();
191
    private final Set<Long> onStack = new HashSet<>();
192
    private final Deque<Long> stack = new ArrayDeque<>();
193
    private final Map<Long, Long> sccId = new HashMap<>();
194
    private int counter = 0;
195
196
    TarjanState(Map<Long, List<Long>> adjacency) {
197
      this.adjacency = adjacency;
198
    }
199
200
    void strongConnect(Long v) {
201
      index.put(v, counter);
202
      lowlink.put(v, counter);
203 1 1. strongConnect : Replaced integer addition with subtraction → KILLED
      counter++;
204 1 1. strongConnect : removed call to java/util/Deque::push → KILLED
      stack.push(v);
205
      onStack.add(v);
206
207
      for (Long w : adjacency.getOrDefault(v, List.of())) {
208 1 1. strongConnect : negated conditional → KILLED
        if (!index.containsKey(w)) {
209 1 1. strongConnect : removed call to edu/ucsb/cs/scaffold/services/ConceptGraphService$TarjanState::strongConnect → KILLED
          strongConnect(w);
210
          lowlink.put(v, Math.min(lowlink.get(v), lowlink.get(w)));
211 1 1. strongConnect : negated conditional → KILLED
        } else if (onStack.contains(w)) {
212
          lowlink.put(v, Math.min(lowlink.get(v), index.get(w)));
213
        }
214
      }
215
216 1 1. strongConnect : negated conditional → KILLED
      if (lowlink.get(v).equals(index.get(v))) {
217
        Long w;
218
        do {
219
          w = stack.pop();
220
          onStack.remove(w);
221
          // v is this component's root: every member gets tagged with its id.
222
          sccId.put(w, v);
223 1 1. strongConnect : negated conditional → KILLED
        } while (!w.equals(v));
224
      }
225
    }
226
  }
227
228
  /**
229
   * An edge u-&gt;v is redundant if some other direct successor w of u can also reach v; such an
230
   * edge is a "shortcut" whose removal does not change reachability. Requires an acyclic edge set.
231
   */
232
  private Set<Long> computeTransitiveReductionRemovals(
233
      Set<Long> nodeIds, List<ConceptEdge> acyclicEdges) {
234
    Map<Long, List<Long>> adjacency = buildAdjacency(acyclicEdges);
235
    Map<Long, Set<Long>> reachable = new HashMap<>();
236
    for (Long node : nodeIds) {
237
      reachable.put(node, bfsReachable(node, adjacency));
238
    }
239
240
    Set<Long> removed = new HashSet<>();
241
    for (ConceptEdge edge : acyclicEdges) {
242
      Long u = edge.getSource().getId();
243
      Long v = edge.getTarget().getId();
244
      boolean redundant =
245
          adjacency.getOrDefault(u, List.of()).stream()
246 3 1. lambda$computeTransitiveReductionRemovals$3 : replaced boolean return with true for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$computeTransitiveReductionRemovals$3 → KILLED
2. lambda$computeTransitiveReductionRemovals$3 : negated conditional → KILLED
3. lambda$computeTransitiveReductionRemovals$3 : negated conditional → KILLED
              .anyMatch(w -> !w.equals(v) && reachable.getOrDefault(w, Set.of()).contains(v));
247 1 1. computeTransitiveReductionRemovals : negated conditional → KILLED
      if (redundant) {
248
        removed.add(edge.getId());
249
      }
250
    }
251 1 1. computeTransitiveReductionRemovals : replaced return value with Collections.emptySet for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeTransitiveReductionRemovals → KILLED
    return removed;
252
  }
253
254
  /**
255
   * Longest path from any root (no incoming edge) to each node; roots are level 1. Requires an
256
   * acyclic edge set.
257
   */
258
  private Map<Long, Integer> computeLongestPathLevels(Set<Long> nodeIds, List<ConceptEdge> edges) {
259
    Map<Long, List<Long>> outNeighbors = buildAdjacency(edges);
260
    Map<Long, Integer> inDegree = new HashMap<>();
261
    for (Long node : nodeIds) {
262
      inDegree.put(node, 0);
263
    }
264
    for (ConceptEdge edge : edges) {
265
      inDegree.merge(edge.getTarget().getId(), 1, Integer::sum);
266
    }
267
268
    Map<Long, Integer> level = new HashMap<>();
269
    Deque<Long> queue = new ArrayDeque<>();
270
    for (Long node : nodeIds) {
271
      level.put(node, 1);
272 1 1. computeLongestPathLevels : negated conditional → KILLED
      if (inDegree.get(node) == 0) {
273
        queue.add(node);
274
      }
275
    }
276
277 1 1. computeLongestPathLevels : negated conditional → TIMED_OUT
    while (!queue.isEmpty()) {
278
      Long u = queue.poll();
279
      for (Long v : outNeighbors.getOrDefault(u, List.of())) {
280 1 1. computeLongestPathLevels : Replaced integer addition with subtraction → KILLED
        level.put(v, Math.max(level.get(v), level.get(u) + 1));
281 1 1. computeLongestPathLevels : negated conditional → KILLED
        if (inDegree.merge(v, -1, Integer::sum) == 0) {
282
          queue.add(v);
283
        }
284
      }
285
    }
286 1 1. computeLongestPathLevels : replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeLongestPathLevels → KILLED
    return level;
287
  }
288
289
  private Set<Long> bfsReachable(Long start, Map<Long, List<Long>> adjacency) {
290
    Set<Long> visited = new HashSet<>(adjacency.getOrDefault(start, List.of()));
291
    Deque<Long> queue = new ArrayDeque<>(visited);
292 1 1. bfsReachable : negated conditional → TIMED_OUT
    while (!queue.isEmpty()) {
293
      Long current = queue.poll();
294
      for (Long next : adjacency.getOrDefault(current, List.of())) {
295 1 1. bfsReachable : negated conditional → TIMED_OUT
        if (visited.add(next)) {
296
          queue.add(next);
297
        }
298
      }
299
    }
300 1 1. bfsReachable : replaced return value with Collections.emptySet for edu/ucsb/cs/scaffold/services/ConceptGraphService::bfsReachable → KILLED
    return visited;
301
  }
302
303
  private Map<Long, List<Long>> buildAdjacency(List<ConceptEdge> edges) {
304
    Map<Long, List<Long>> adjacency = new HashMap<>();
305
    for (ConceptEdge edge : edges) {
306
      adjacency
307 1 1. lambda$buildAdjacency$4 : replaced return value with Collections.emptyList for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$buildAdjacency$4 → KILLED
          .computeIfAbsent(edge.getSource().getId(), k -> new ArrayList<>())
308
          .add(edge.getTarget().getId());
309
    }
310 1 1. buildAdjacency : replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::buildAdjacency → KILLED
    return adjacency;
311
  }
312
}

Mutations

43

1.1
Location : colorForLevel
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:colorForLevel_clamps_a_non_positive_level_to_level_one()]
Replaced integer subtraction with addition → KILLED

44

1.1
Location : colorForLevel
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:colorForLevel_clamps_a_non_positive_level_to_level_one()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/ConceptGraphService::colorForLevel → KILLED

58

1.1
Location : wouldCreateCycle
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:wouldCreateCycle_is_true_when_the_target_can_reach_the_source_transitively()]
negated conditional → KILLED

60

1.1
Location : wouldCreateCycle
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:wouldCreateCycle_is_false_when_there_are_no_existing_edges()]
negated conditional → KILLED

61

1.1
Location : wouldCreateCycle
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:wouldCreateCycle_is_true_when_the_target_can_reach_the_source_transitively()]
replaced boolean return with false for edu/ucsb/cs/scaffold/services/ConceptGraphService::wouldCreateCycle → KILLED

64

1.1
Location : wouldCreateCycle
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:wouldCreateCycle_is_true_when_the_target_can_reach_the_source_transitively()]
negated conditional → KILLED

69

1.1
Location : wouldCreateCycle
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:wouldCreateCycle_is_false_when_there_are_no_existing_edges()]
replaced boolean return with true for edu/ucsb/cs/scaffold/services/ConceptGraphService::wouldCreateCycle → KILLED

92

1.1
Location : reset
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
replaced return value with null for edu/ucsb/cs/scaffold/services/ConceptGraphService::reset → KILLED

109

1.1
Location : lambda$reset$0
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
replaced Long return value with 0L for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$reset$0 → KILLED

117

1.1
Location : reset
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
negated conditional → KILLED

2.2
Location : reset
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_does_not_treat_a_self_loop_as_a_cycle()]
changed conditional boundary → KILLED

3.3
Location : reset
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
negated conditional → KILLED

118

1.1
Location : reset
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
negated conditional → KILLED

135

1.1
Location : reset
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
replaced return value with null for edu/ucsb/cs/scaffold/services/ConceptGraphService::reset → KILLED

149

1.1
Location : lambda$computeLayout$1
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
replaced Integer return value with 0 for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$computeLayout$1 → KILLED

157

1.1
Location : lambda$computeLayout$2
Killed by : edu.ucsb.cs.scaffold.controller.ConceptsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.controller.ConceptsControllerTests]/[method:reset_falls_back_to_saved_x_when_the_override_has_no_x_value()]
replaced Integer return value with 0 for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$computeLayout$2 → KILLED

161

1.1
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
Replaced integer subtraction with addition → KILLED

2.2
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_ranks_a_linear_chain_by_longest_path_and_stacks_levels_vertically()]
removed negation → KILLED

3.3
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_ranks_a_linear_chain_by_longest_path_and_stacks_levels_vertically()]
Replaced integer multiplication with division → KILLED

162

1.1
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
changed conditional boundary → KILLED

2.2
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
negated conditional → KILLED

163

1.1
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_lays_out_multiple_concepts_at_the_same_level_centered_and_separated()]
Replaced double multiplication with division → KILLED

2.2
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
Replaced integer subtraction with addition → KILLED

3.3
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_lays_out_multiple_concepts_at_the_same_level_centered_and_separated()]
Replaced double subtraction with addition → KILLED

4.4
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_lays_out_multiple_concepts_at_the_same_level_centered_and_separated()]
Replaced double division with multiplication → KILLED

167

1.1
Location : computeLayout
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeLayout → KILLED

180

1.1
Location : computeStronglyConnectedComponents
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
negated conditional → KILLED

181

1.1
Location : computeStronglyConnectedComponents
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
removed call to edu/ucsb/cs/scaffold/services/ConceptGraphService$TarjanState::strongConnect → KILLED

184

1.1
Location : computeStronglyConnectedComponents
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeStronglyConnectedComponents → KILLED

203

1.1
Location : strongConnect
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
Replaced integer addition with subtraction → KILLED

204

1.1
Location : strongConnect
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
removed call to java/util/Deque::push → KILLED

208

1.1
Location : strongConnect
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
negated conditional → KILLED

209

1.1
Location : strongConnect
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
removed call to edu/ucsb/cs/scaffold/services/ConceptGraphService$TarjanState::strongConnect → KILLED

211

1.1
Location : strongConnect
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
negated conditional → KILLED

216

1.1
Location : strongConnect
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_flags_edges_in_two_separate_disjoint_cycles_independently()]
negated conditional → KILLED

223

1.1
Location : strongConnect
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
negated conditional → KILLED

246

1.1
Location : lambda$computeTransitiveReductionRemovals$3
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
replaced boolean return with true for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$computeTransitiveReductionRemovals$3 → KILLED

2.2
Location : lambda$computeTransitiveReductionRemovals$3
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
negated conditional → KILLED

3.3
Location : lambda$computeTransitiveReductionRemovals$3
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
negated conditional → KILLED

247

1.1
Location : computeTransitiveReductionRemovals
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
negated conditional → KILLED

251

1.1
Location : computeTransitiveReductionRemovals
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
replaced return value with Collections.emptySet for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeTransitiveReductionRemovals → KILLED

272

1.1
Location : computeLongestPathLevels
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
negated conditional → KILLED

277

1.1
Location : computeLongestPathLevels
Killed by : none
negated conditional → TIMED_OUT

280

1.1
Location : computeLongestPathLevels
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
Replaced integer addition with subtraction → KILLED

281

1.1
Location : computeLongestPathLevels
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
negated conditional → KILLED

286

1.1
Location : computeLongestPathLevels
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_centers_a_single_concept_at_a_level_on_x_zero()]
replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::computeLongestPathLevels → KILLED

292

1.1
Location : bfsReachable
Killed by : none
negated conditional → TIMED_OUT

295

1.1
Location : bfsReachable
Killed by : none
negated conditional → TIMED_OUT

300

1.1
Location : bfsReachable
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:reset_removes_a_direct_edge_made_redundant_by_a_longer_path()]
replaced return value with Collections.emptySet for edu/ucsb/cs/scaffold/services/ConceptGraphService::bfsReachable → KILLED

307

1.1
Location : lambda$buildAdjacency$4
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:wouldCreateCycle_is_false_when_the_target_cannot_reach_the_source()]
replaced return value with Collections.emptyList for edu/ucsb/cs/scaffold/services/ConceptGraphService::lambda$buildAdjacency$4 → KILLED

310

1.1
Location : buildAdjacency
Killed by : edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.ConceptGraphServiceTests]/[method:wouldCreateCycle_is_true_when_the_target_can_reach_the_source_transitively()]
replaced return value with Collections.emptyMap for edu/ucsb/cs/scaffold/services/ConceptGraphService::buildAdjacency → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0