handle comparison of non-polarized components

This commit is contained in:
Bane Stojkovic
2025-05-18 23:54:43 +02:00
parent 5456f2819b
commit f88f867bf4
2 changed files with 434 additions and 5 deletions
@@ -35,8 +35,10 @@ import org.diylc.presenter.Presenter;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -179,6 +181,134 @@ public class CompareService {
}
}
// Try to resolve differences by flipping non-polarized components
if (!connectionDiffs.isEmpty()) {
// Find all non-polarized components that have nodes in different groups
Map<String, List<Group>> componentGroups = new HashMap<>();
for (Group group : groups1) {
for (Node node : group.getNodes()) {
if (!node.getComponent().isPolarized()) {
componentGroups.computeIfAbsent(node.getComponent().getName(), k -> new ArrayList<>())
.add(group);
}
}
}
// Try swapping nodes for each non-polarized component that appears in multiple groups
for (Map.Entry<String, List<Group>> entry : componentGroups.entrySet()) {
if (entry.getValue().size() >= 2) {
String componentName = entry.getKey();
List<Group> groupsWithComponent = entry.getValue();
// Get the nodes from the first two groups
Group group1 = groupsWithComponent.get(0);
Group group2 = groupsWithComponent.get(1);
Node node1 = group1.getNodes().stream()
.filter(n -> n.getComponent().getName().equals(componentName))
.findFirst()
.get();
Node node2 = group2.getNodes().stream()
.filter(n -> n.getComponent().getName().equals(componentName))
.findFirst()
.get();
// Create new groups with swapped nodes
Group newGroup1 = new Group();
Group newGroup2 = new Group();
// Copy all nodes except the ones we're swapping
for (Node n : group1.getNodes()) {
if (!n.getComponent().getName().equals(componentName)) {
newGroup1.getNodes().add(n);
}
}
for (Node n : group2.getNodes()) {
if (!n.getComponent().getName().equals(componentName)) {
newGroup2.getNodes().add(n);
}
}
// Add the swapped nodes
newGroup1.getNodes().add(node2);
newGroup2.getNodes().add(node1);
// Create a new set of groups with the swapped nodes
Set<Group> newGroups1 = new HashSet<>(groups1);
newGroups1.remove(group1);
newGroups1.remove(group2);
newGroups1.add(newGroup1);
newGroups1.add(newGroup2);
// Check if this resolves ALL differences
List<ConnectionDiff> newDiffs = new ArrayList<>();
Set<ComponentDiff> newComponentDiffs = new HashSet<>();
// Check groups from netlist1 against netlist2
for (Group g1 : newGroups1) {
boolean groupFound = false;
for (Group g2 : groups2) {
if (areGroupsEqual(g1, g2)) {
groupFound = true;
break;
}
}
if (!groupFound) {
// Add connection differences for this group
List<Node> nodes = new ArrayList<>(g1.getNodes());
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i);
for (int j = i + 1; j < nodes.size(); j++) {
Node otherNode = nodes.get(j);
newDiffs.add(new ConnectionDiff(
node.getComponent().getName(),
node.getComponent().getControlPointNodeName(node.getPointIndex()),
otherNode.getComponent().getName(),
otherNode.getComponent().getControlPointNodeName(otherNode.getPointIndex()),
true));
}
}
}
}
// Check groups from netlist2 against netlist1
for (Group g2 : groups2) {
boolean groupFound = false;
for (Group g1 : newGroups1) {
if (areGroupsEqual(g1, g2)) {
groupFound = true;
break;
}
}
if (!groupFound) {
// Add connection differences for this group
List<Node> nodes = new ArrayList<>(g2.getNodes());
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i);
for (int j = i + 1; j < nodes.size(); j++) {
Node otherNode = nodes.get(j);
newDiffs.add(new ConnectionDiff(
node.getComponent().getName(),
node.getComponent().getControlPointNodeName(node.getPointIndex()),
otherNode.getComponent().getName(),
otherNode.getComponent().getControlPointNodeName(otherNode.getPointIndex()),
false));
}
}
}
}
// If this swap resolved all differences, use the new groups
if (newDiffs.isEmpty() && newComponentDiffs.isEmpty()) {
groups1 = newGroups1;
connectionDiffs = new ArrayList<>();
componentDiffs = new HashSet<>();
break;
}
}
}
}
if (connectionDiffs.isEmpty() && componentDiffs.isEmpty()) {
return new CompareResults(true, List.of(), List.of());
}
@@ -194,13 +324,25 @@ public class CompareService {
java.util.function.Function<Node, String> nodeKey = node ->
node.getComponent().getName() + ":" + node.getComponent().getControlPointNodeName(node.getPointIndex());
Set<String> group1Keys = group1.getNodes().stream()
// For polarized components, we need to check exact node order
List<String> group1Keys = group1.getNodes().stream()
.map(nodeKey)
.collect(Collectors.toSet());
Set<String> group2Keys = group2.getNodes().stream()
.collect(Collectors.toList());
List<String> group2Keys = group2.getNodes().stream()
.map(nodeKey)
.collect(Collectors.toSet());
.collect(Collectors.toList());
return group1Keys.equals(group2Keys);
// If any component in the group is polarized, we need exact order match
boolean hasPolarizedComponent = group1.getNodes().stream()
.anyMatch(node -> node.getComponent().isPolarized()) ||
group2.getNodes().stream()
.anyMatch(node -> node.getComponent().isPolarized());
if (hasPolarizedComponent) {
return group1Keys.equals(group2Keys);
}
// For non-polarized components, we can use unordered comparison
return new HashSet<>(group1Keys).equals(new HashSet<>(group2Keys));
}
}
@@ -187,6 +187,291 @@ public class CompareServiceTest {
assertEquals(4, results.connectionDiffs().size());
}
@Test
public void testCompare_NonPolarizedComponent_SwappedNodes() {
Map<String, IDIYComponent<?>> componentMap = new HashMap<>();
// Create first netlist with non-polarized component in two groups
Netlist netlist1 = new Netlist(new ArrayList<>());
netlist1.add(createGroup(componentMap, "Resistor1", "Node1", "Component2", "Node2"));
netlist1.add(createGroup(componentMap, "Resistor1", "Node2", "Component3", "Node3"));
// Create second netlist with same connections but different node order
Netlist netlist2 = new Netlist(new ArrayList<>());
netlist2.add(createGroup(componentMap, "Resistor1", "Node2", "Component2", "Node2"));
netlist2.add(createGroup(componentMap, "Resistor1", "Node1", "Component3", "Node3"));
// Make Resistor1 non-polarized
IDIYComponent<?> resistor = componentMap.get("Resistor1");
when(resistor.isPolarized()).thenReturn(false);
CompareResults results = compareService.compare(netlist1, netlist2);
assertTrue(results.matches());
assertTrue(results.connectionDiffs().isEmpty());
assertTrue(results.componentDiffs().isEmpty());
}
@Test
public void testCompare_PolarizedComponent_SwappedNodes() {
// Create first netlist with polarized component in two groups
Netlist netlist1 = new Netlist(new ArrayList<>());
// Create diode for netlist1
IDIYComponent<?> diode1 = mock(IDIYComponent.class);
when(diode1.getName()).thenReturn("Diode1");
when(diode1.getControlPointCount()).thenReturn(2);
when(diode1.getControlPoint(0)).thenReturn(new Point2D.Double(0, 0));
when(diode1.getControlPoint(1)).thenReturn(new Point2D.Double(0, 0));
when(diode1.isControlPointSticky(0)).thenReturn(true);
when(diode1.isControlPointSticky(1)).thenReturn(true);
when(diode1.isPolarized()).thenReturn(true);
when(diode1.toString()).thenReturn("Diode1");
when(diode1.getControlPointNodeName(0)).thenReturn("Anode");
when(diode1.getControlPointNodeName(1)).thenReturn("Cathode");
// Create Component2 for netlist1
IDIYComponent<?> component2_1 = mock(IDIYComponent.class);
when(component2_1.getName()).thenReturn("Component2");
when(component2_1.getControlPointNodeName(0)).thenReturn("Node2");
when(component2_1.getControlPointCount()).thenReturn(1);
when(component2_1.getControlPoint(0)).thenReturn(new Point2D.Double(0, 0));
when(component2_1.isControlPointSticky(0)).thenReturn(true);
when(component2_1.toString()).thenReturn("Component2");
when(component2_1.isPolarized()).thenReturn(false);
// Create Component3 for netlist1
IDIYComponent<?> component3_1 = mock(IDIYComponent.class);
when(component3_1.getName()).thenReturn("Component3");
when(component3_1.getControlPointNodeName(0)).thenReturn("Node3");
when(component3_1.getControlPointCount()).thenReturn(1);
when(component3_1.getControlPoint(0)).thenReturn(new Point2D.Double(0, 0));
when(component3_1.isControlPointSticky(0)).thenReturn(true);
when(component3_1.toString()).thenReturn("Component3");
when(component3_1.isPolarized()).thenReturn(false);
// Create groups for netlist1
Group group1 = new Group();
Node node1 = new Node(diode1, 0); // Anode
Node node2 = new Node(component2_1, 0);
group1.getNodes().add(node1);
group1.getNodes().add(node2);
netlist1.add(group1);
Group group2 = new Group();
Node node3 = new Node(diode1, 1); // Cathode
Node node4 = new Node(component3_1, 0);
group2.getNodes().add(node3);
group2.getNodes().add(node4);
netlist1.add(group2);
// Create second netlist with same connections but different node order
Netlist netlist2 = new Netlist(new ArrayList<>());
// Create diode for netlist2
IDIYComponent<?> diode2 = mock(IDIYComponent.class);
when(diode2.getName()).thenReturn("Diode1");
when(diode2.getControlPointCount()).thenReturn(2);
when(diode2.getControlPoint(0)).thenReturn(new Point2D.Double(0, 0));
when(diode2.getControlPoint(1)).thenReturn(new Point2D.Double(0, 0));
when(diode2.isControlPointSticky(0)).thenReturn(true);
when(diode2.isControlPointSticky(1)).thenReturn(true);
when(diode2.isPolarized()).thenReturn(true);
when(diode2.toString()).thenReturn("Diode1");
when(diode2.getControlPointNodeName(0)).thenReturn("Anode");
when(diode2.getControlPointNodeName(1)).thenReturn("Cathode");
// Create Component2 for netlist2
IDIYComponent<?> component2_2 = mock(IDIYComponent.class);
when(component2_2.getName()).thenReturn("Component2");
when(component2_2.getControlPointNodeName(0)).thenReturn("Node2");
when(component2_2.getControlPointCount()).thenReturn(1);
when(component2_2.getControlPoint(0)).thenReturn(new Point2D.Double(0, 0));
when(component2_2.isControlPointSticky(0)).thenReturn(true);
when(component2_2.toString()).thenReturn("Component2");
when(component2_2.isPolarized()).thenReturn(false);
// Create Component3 for netlist2
IDIYComponent<?> component3_2 = mock(IDIYComponent.class);
when(component3_2.getName()).thenReturn("Component3");
when(component3_2.getControlPointNodeName(0)).thenReturn("Node3");
when(component3_2.getControlPointCount()).thenReturn(1);
when(component3_2.getControlPoint(0)).thenReturn(new Point2D.Double(0, 0));
when(component3_2.isControlPointSticky(0)).thenReturn(true);
when(component3_2.toString()).thenReturn("Component3");
when(component3_2.isPolarized()).thenReturn(false);
// Create groups for netlist2 with swapped nodes
Group group3 = new Group();
Node node5 = new Node(diode2, 1); // Cathode
Node node6 = new Node(component2_2, 0);
group3.getNodes().add(node5);
group3.getNodes().add(node6);
netlist2.add(group3);
Group group4 = new Group();
Node node7 = new Node(diode2, 0); // Anode
Node node8 = new Node(component3_2, 0);
group4.getNodes().add(node7);
group4.getNodes().add(node8);
netlist2.add(group4);
// Debug: Print the groups and verify diode polarity
System.out.println("Netlist1 groups:");
for (Group g : netlist1.getGroups()) {
System.out.println("Group: " + g);
for (Node n : g.getNodes()) {
System.out.println(" Node: " + n.getComponent().getName() +
" " + n.getComponent().getControlPointNodeName(n.getPointIndex()) +
" (polarized: " + n.getComponent().isPolarized() + ")");
}
}
System.out.println("\nNetlist2 groups:");
for (Group g : netlist2.getGroups()) {
System.out.println("Group: " + g);
for (Node n : g.getNodes()) {
System.out.println(" Node: " + n.getComponent().getName() +
" " + n.getComponent().getControlPointNodeName(n.getPointIndex()) +
" (polarized: " + n.getComponent().isPolarized() + ")");
}
}
CompareResults results = compareService.compare(netlist1, netlist2);
// Debug: Print comparison results
System.out.println("\nComparison results:");
System.out.println("Matches: " + results.matches());
System.out.println("Component diffs: " + results.componentDiffs().size());
System.out.println("Connection diffs: " + results.connectionDiffs().size());
for (ConnectionDiff diff : results.connectionDiffs()) {
System.out.println(" " + diff.fromComponent() + " " + diff.fromNodeName() +
" -> " + diff.toComponent() + " " + diff.toNodeName() +
" (present in current: " + diff.presentInCurrent() + ")");
}
assertTrue(!results.matches());
assertEquals(0, results.componentDiffs().size());
// Since connections are reported in both directions, we expect 4 differences
assertEquals(4, results.connectionDiffs().size());
// Verify the specific differences
List<ConnectionDiff> diffs = results.connectionDiffs();
boolean foundCathodeToComponent3 = false;
boolean foundComponent3ToCathode = false;
boolean foundComponent2ToAnode = false;
boolean foundAnodeToComponent2 = false;
boolean foundCathodeToComponent2 = false;
boolean foundComponent2ToCathode = false;
boolean foundAnodeToComponent3 = false;
boolean foundComponent3ToAnode = false;
for (ConnectionDiff diff : diffs) {
// Check Diode1 Cathode <-> Component3 Node3
if (diff.fromComponent().equals("Diode1") &&
diff.fromNodeName().equals("Cathode") &&
diff.toComponent().equals("Component3") &&
diff.toNodeName().equals("Node3") &&
diff.presentInCurrent()) {
foundCathodeToComponent3 = true;
}
if (diff.fromComponent().equals("Component3") &&
diff.fromNodeName().equals("Node3") &&
diff.toComponent().equals("Diode1") &&
diff.toNodeName().equals("Cathode") &&
diff.presentInCurrent()) {
foundComponent3ToCathode = true;
}
// Check Component2 Node2 <-> Diode1 Anode
if (diff.fromComponent().equals("Component2") &&
diff.fromNodeName().equals("Node2") &&
diff.toComponent().equals("Diode1") &&
diff.toNodeName().equals("Anode") &&
diff.presentInCurrent()) {
foundComponent2ToAnode = true;
}
if (diff.fromComponent().equals("Diode1") &&
diff.fromNodeName().equals("Anode") &&
diff.toComponent().equals("Component2") &&
diff.toNodeName().equals("Node2") &&
diff.presentInCurrent()) {
foundAnodeToComponent2 = true;
}
// Check Diode1 Cathode <-> Component2 Node2 (not present)
if (diff.fromComponent().equals("Diode1") &&
diff.fromNodeName().equals("Cathode") &&
diff.toComponent().equals("Component2") &&
diff.toNodeName().equals("Node2") &&
!diff.presentInCurrent()) {
foundCathodeToComponent2 = true;
}
if (diff.fromComponent().equals("Component2") &&
diff.fromNodeName().equals("Node2") &&
diff.toComponent().equals("Diode1") &&
diff.toNodeName().equals("Cathode") &&
!diff.presentInCurrent()) {
foundComponent2ToCathode = true;
}
// Check Diode1 Anode <-> Component3 Node3 (not present)
if (diff.fromComponent().equals("Diode1") &&
diff.fromNodeName().equals("Anode") &&
diff.toComponent().equals("Component3") &&
diff.toNodeName().equals("Node3") &&
!diff.presentInCurrent()) {
foundAnodeToComponent3 = true;
}
if (diff.fromComponent().equals("Component3") &&
diff.fromNodeName().equals("Node3") &&
diff.toComponent().equals("Diode1") &&
diff.toNodeName().equals("Anode") &&
!diff.presentInCurrent()) {
foundComponent3ToAnode = true;
}
}
// Check that we found at least one direction of each connection
assertTrue("Should detect difference in Diode1 Cathode <-> Component3 Node3 (present in current)",
foundCathodeToComponent3 || foundComponent3ToCathode);
assertTrue("Should detect difference in Component2 Node2 <-> Diode1 Anode (present in current)",
foundComponent2ToAnode || foundAnodeToComponent2);
assertTrue("Should detect difference in Diode1 Cathode <-> Component2 Node2 (not present in current)",
foundCathodeToComponent2 || foundComponent2ToCathode);
assertTrue("Should detect difference in Diode1 Anode <-> Component3 Node3 (not present in current)",
foundAnodeToComponent3 || foundComponent3ToAnode);
}
@Test
public void testCompare_MixedPolarizedAndNonPolarized() {
Map<String, IDIYComponent<?>> componentMap = new HashMap<>();
// Create first netlist with both polarized and non-polarized components
Netlist netlist1 = new Netlist(new ArrayList<>());
netlist1.add(createGroup(componentMap, "Resistor1", "Node1", "Diode1", "Anode"));
netlist1.add(createGroup(componentMap, "Resistor1", "Node2", "Component3", "Node3"));
netlist1.add(createGroup(componentMap, "Diode1", "Cathode", "Component4", "Node4"));
// Create second netlist with same connections but different node order for non-polarized
Netlist netlist2 = new Netlist(new ArrayList<>());
netlist2.add(createGroup(componentMap, "Resistor1", "Node2", "Diode1", "Anode"));
netlist2.add(createGroup(componentMap, "Resistor1", "Node1", "Component3", "Node3"));
netlist2.add(createGroup(componentMap, "Diode1", "Cathode", "Component4", "Node4"));
// Make Resistor1 non-polarized and Diode1 polarized
IDIYComponent<?> resistor = componentMap.get("Resistor1");
IDIYComponent<?> diode = componentMap.get("Diode1");
when(resistor.isPolarized()).thenReturn(false);
when(diode.isPolarized()).thenReturn(true);
CompareResults results = compareService.compare(netlist1, netlist2);
assertTrue(results.matches());
assertTrue(results.connectionDiffs().isEmpty());
assertTrue(results.componentDiffs().isEmpty());
}
private Netlist createNetlist(Map<String, IDIYComponent<?>> componentMap, String... componentNodePairs) {
Netlist netlist = new Netlist(new ArrayList<>());
netlist.add(createGroup(componentMap, componentNodePairs));
@@ -208,6 +493,8 @@ public class CompareServiceTest {
when(c.getControlPoint(0)).thenReturn(new Point2D.Double(0, 0));
when(c.isControlPointSticky(0)).thenReturn(true);
when(c.toString()).thenReturn(name);
// Default to non-polarized
when(c.isPolarized()).thenReturn(false);
return c;
});
// For the same component name, update the node name for this instance