From 4aa8a72769106e22864ba7bbc3de11025b3c55a7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 19 May 2021 14:56:38 -0400 Subject: [PATCH] Corrected an error found in ResolveAutomorphsByProperty which would cause inexplicable output in case of a property error by showing a netlist topography error instead of a property error (but the output shows that the netlists match, and there is no reporting of any property errors). This error was discovered while implementing a better sorting method for parallel combination. The improved method sorts on two properties rather than one, and so should not fall into the error where, say, devices are sorted on W but have different L for a device like a capacitor where no "critical" property is specified (and other similar cases, although that is a common one). --- VERSION | 2 +- base/netcmp.c | 148 +++++++++++++++++++++++++--------------------- tcltk/tclnetgen.c | 14 +++-- 3 files changed, 88 insertions(+), 76 deletions(-) diff --git a/VERSION b/VERSION index 8232290..56dd60e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.176 +1.5.177 diff --git a/base/netcmp.c b/base/netcmp.c index 3a29ae4..f984f05 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -4058,24 +4058,33 @@ int series_optimize(struct objlist *ob1, struct nlist *tp1, int idx1, } typedef struct _propsort { - double value; + double value; /* Primary sorting value */ + double avalue; /* Secondary sorting value */ + double slop; /* Delta for accepting equality */ int idx; unsigned char flags; struct objlist *ob; } propsort; /*--------------------------------------------------------------*/ -/* Property sorting routine used by qsort() */ +/* Property sorting routine used by qsort(). Sorts on "value" */ +/* unless the "value" for the two entries differs by less than */ +/* "slop", in which case the entries are sorted on "avalue". */ /*--------------------------------------------------------------*/ static int compsort(const void *p1, const void *p2) { propsort *s1, *s2; + double smax; s1 = (propsort *)p1; s2 = (propsort *)p2; - return (s1->value > s2->value) ? 1 : 0; + smax = fmax(s1->slop, s2->slop); + if (fabs(s1->value - s2->value) <= smax) + return (s1->avalue > s2->avalue) ? 1 : 0; + else + return (s1->value > s2->value) ? 1 : 0; } /*--------------------------------------------------------------*/ @@ -4094,7 +4103,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) struct property *kl; struct valuelist *vl, *sl; int i, p, sval, merge_type; - double cval; + double cval, slop; obn = ob1->next; for (i = 0; i < idx1; i++) obn = obn->next; @@ -4107,7 +4116,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) obp = obn; sval = 1; - cval = 0.0; + cval = slop = 0.0; for (i = 0; i < run; i++) { merge_type = MERGE_NONE; for (p = 0;; p++) { @@ -4121,24 +4130,35 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) else { kl = (struct property *)HashLookup(vl->key, &(tp1->propdict)); if (kl && (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))) { - if (vl->type == PROP_INTEGER) + if (vl->type == PROP_INTEGER) { cval = (double)vl->value.ival; - else + slop = (double)kl->slop.ival; + } + else { cval = vl->value.dval; + slop = kl->slop.dval; + } merge_type = kl->merge & (MERGE_S_ADD | MERGE_S_PAR); } } } if (merge_type == MERGE_S_ADD) { proplist[i].value = cval * (double)sval; + proplist[i].slop = slop; + proplist[i].avalue = 0; sl->value.ival = 1; } else if (merge_type == MERGE_S_PAR) { proplist[i].value = cval / (double)sval; + proplist[i].slop = slop; + proplist[i].avalue = 0; sl->value.ival = 1; } else { + /* Components which declare no series addition method stay unsorted */ proplist[i].value = (double)0; + proplist[i].avalue = (double)0; + proplist[i].slop = (double)1E-6; } proplist[i].idx = i; proplist[i].ob = obp; @@ -4236,8 +4256,8 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) struct property *kl; struct valuelist *vl, *ml; int i, p, mval, merge_type, has_crit = FALSE; - char *subs_crit = NULL; - double cval; + char c, *subs_crit = NULL; + double cval, tval, aval, slop, tslop; obn = ob1->next; for (i = 0; i < idx1; i++) obn = obn->next; @@ -4258,10 +4278,11 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) obp = obn; mval = 1; - cval = 0.0; + cval = aval = slop = 0.0; for (i = 0; i < run; i++) { merge_type = MERGE_NONE; ml = NULL; + c = (char)0; for (p = 0;; p++) { vl = &(obp->instance.props[p]); if (vl->type == PROP_ENDLIST) break; @@ -4278,84 +4299,71 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) && (kl->type != vl->type)) PromoteProperty(kl, vl); - if (vl->type == PROP_INTEGER) - cval = (double)vl->value.ival; - else if (vl->type == PROP_STRING) + if (vl->type == PROP_INTEGER) { + tval = (double)vl->value.ival; + tslop = (double)kl->slop.ival; + } + else if (vl->type == PROP_STRING) { /* This is unlikely---no method to merge string properties! */ - cval = (double)vl->value.string[0] + tval = (double)vl->value.string[0] + (double)vl->value.string[1] / 10.0; - else - cval = vl->value.dval; + tslop = (double)0; + } + else { + tval = vl->value.dval; + tslop = kl->slop.dval; + } - merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR); + if (merge_type == MERGE_NONE) + { + merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR); + cval = tval; + slop = tslop; + } + else { + if ((c == (char)0) || (toupper(vl->key[0]) > c)) { + c = toupper(vl->key[0]); + aval = tval; + } + } } + else { + if ((c == (char)0) || (toupper(vl->key[0]) > c)) { + if (vl->type == PROP_INTEGER) { + aval = (double)vl->value.ival; + c = toupper(vl->key[0]); + } + else if (vl->type == PROP_DOUBLE) { + aval = vl->value.dval; + c = toupper(vl->key[0]); + } + } + } } if (merge_type == MERGE_P_ADD) { proplist[i].value = cval * (double)mval; + proplist[i].avalue = aval; + proplist[i].slop = tslop; if (ml) ml->value.ival = 1; } else if (merge_type == MERGE_P_PAR) { proplist[i].value = cval / (double)mval; + proplist[i].avalue = aval; + proplist[i].slop = tslop; if (ml) ml->value.ival = 1; } else { - proplist[i].value = (double)0; + /* If there are no additive values, then sort first by M */ + /* and second by aval */ + proplist[i].value = (double)mval; + proplist[i].avalue = aval; + proplist[i].slop = (double)0; } proplist[i].idx = i; proplist[i].ob = obp; obp = obp->next; } - if (has_crit == FALSE) { - /* If no critical property was specified, then choose the first one found */ - /* and recalculate all the proplist values. */ - mval = 1; - obp = obn; - ml = NULL; - merge_type = MERGE_NONE; - for (i = 0; i < run; i++) { - for (p = 0;; p++) { - vl = &(obp->instance.props[p]); - if (vl->type == PROP_ENDLIST) break; - if (vl->key == NULL) continue; - if ((*matchfunc)(vl->key, "M")) { - mval = vl->value.ival; - ml = vl; - } - kl = (struct property *)HashLookup(vl->key, &(tp1->propdict)); - if (kl == NULL) continue; /* Ignored property */ - if (subs_crit == NULL) - subs_crit = vl->key; - if ((subs_crit != NULL) && (*matchfunc)(vl->key, subs_crit)) { - if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) && - (kl->type != vl->type)) - PromoteProperty(kl, vl); - if (vl->type == PROP_INTEGER) - cval = (double)vl->value.ival; - else if (vl->type == PROP_STRING) - /* In case property is non-numeric, sort by dictionary order */ - cval = (double)vl->value.string[0] - + (double)vl->value.string[1] / 10.0; - else - cval = vl->value.dval; - merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR); - } - } - if (merge_type == MERGE_P_ADD) { - proplist[i].value = cval * (double)mval; - if (ml) ml->value.ival = 1; - } - else if (merge_type == MERGE_P_PAR) { - proplist[i].value = cval / (double)mval; - if (ml) ml->value.ival = 1; - } - else { - proplist[i].value = 0; - } - obp = obp->next; - } - } - obn = obp; /* Link from last property */ qsort(&proplist[0], run, sizeof(propsort), compsort); @@ -4846,7 +4854,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series, } // Additive properties do not need to be matched, since - // they can be combined. Critical paroperties must be + // they can be combined. Critical properties must be // matched. Properties with no merge behavior must match. ctype = clist[p][i]; @@ -6207,6 +6215,7 @@ int ResolveAutomorphsByProperty() if ((E2->graph != E1->graph) && (E2->hashval == newhash)) { E2->hashval = orighash; C2--; + if (C2 == C1) break; } } } @@ -6215,6 +6224,7 @@ int ResolveAutomorphsByProperty() if ((E2->graph == E1->graph) && (E2->hashval == newhash)) { E2->hashval = orighash; C1--; + if (C1 == C2) break; } } } diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index ccab280..79f005a 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -2457,8 +2457,7 @@ _netcmp_run(ClientData clientData, automorphisms = ResolveAutomorphsByProperty(); if (automorphisms == 0) Fprintf(stdout, "Netlists match uniquely.\n"); - else { - + else if (automorphisms > 0) { // Next, attempt to resolve automorphisms uniquely by // using the pin names automorphisms = ResolveAutomorphsByPin(); @@ -2466,14 +2465,17 @@ _netcmp_run(ClientData clientData, if (automorphisms == 0) Fprintf(stdout, "Netlists match uniquely.\n"); - else + else if (automorphisms > 0) { // Anything left is truly indistinguishable Fprintf(stdout, "Netlists match with %d symmetr%s.\n", automorphisms, (automorphisms == 1) ? "y" : "ies"); - while ((automorphisms = ResolveAutomorphisms()) > 0); - if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); - else Fprintf(stdout, "Circuits match correctly.\n"); + while ((automorphisms = ResolveAutomorphisms()) > 0); + } + if (automorphisms == -1) + Fprintf(stdout, "Netlists do not match.\n"); + else + Fprintf(stdout, "Circuits match correctly.\n"); } if (PropertyErrorDetected) { Fprintf(stdout, "There were property errors.\n");