#include #include "system.h" #include "util.h" #include "type.h" #include "network.h" #include "connect.h" #include "control.h" #include "example.h" #include "display.h" #include "parallel.h" #include "graph.h" #define OUTPUT_SCALE 0.7 flag UnitUp; flag LinkUp; char *OutlineColor[NUM_PALETTES][3]; char *ColorMap[NUM_PALETTES][NUM_COLORS]; char *NaNColor = "grey50"; int PlotWidth, Space, ViewTick; flag UnitsNeedRedraw = FALSE, LinksNeedRedraw = FALSE; flag drawUnits(ClientData junk); flag drawLinks(ClientData junk); void fillPalette(int palette) { static char done[4] = {FALSE, FALSE, FALSE, FALSE}; int i, ival; real rval, red, green, blue; char buf[32]; if (done[palette]) return; done[palette] = TRUE; switch (palette) { case BLUE_BLACK_RED: for (i = 0; i < NUM_COLORS; i++) { red = ((real) i / (NUM_COLORS - 1)) * 2 - 1; if (red < 0.0) { blue = -red; red = 0.0; } else blue = 0.0; sprintf(buf, "#%03X000%03X", (int)(red * 4095), (int)(blue * 4095)); ColorMap[BLUE_BLACK_RED][i] = copyString(buf); } OutlineColor[BLUE_BLACK_RED][0] = "black"; OutlineColor[BLUE_BLACK_RED][1] = "yellow"; OutlineColor[BLUE_BLACK_RED][2] = "magenta"; break; case BLUE_RED_YELLOW: for (i = 0; i < NUM_COLORS; i++) { rval = ((real) i / (NUM_COLORS - 1)); if (rval <= 0.5) { green = 0.0; red = rval * 2; blue = 1.0 - red; } else { red = 1.0; blue = 0.0; green = rval * 2 - 1.0; } sprintf(buf, "#%03X%03X%03X", (int)(red * 4095), (int)(green * 4095), (int)(blue * 4095)); ColorMap[BLUE_RED_YELLOW][i] = copyString(buf); } OutlineColor[BLUE_RED_YELLOW][0] = "black"; OutlineColor[BLUE_RED_YELLOW][1] = "white"; OutlineColor[BLUE_RED_YELLOW][1] = "magenta"; break; case BLACK_GRAY_WHITE: for (i = 0; i < NUM_COLORS; i++) { ival = (int) ((real) i / (NUM_COLORS - 1) * 4095); sprintf(buf, "#%03X%03X%03X", ival, ival, ival); ColorMap[BLACK_GRAY_WHITE][i] = copyString(buf); } OutlineColor[BLACK_GRAY_WHITE][0] = "grey50"; OutlineColor[BLACK_GRAY_WHITE][1] = "black"; OutlineColor[BLACK_GRAY_WHITE][1] = "white"; break; case HINTON: OutlineColor[HINTON][0] = "grey50"; OutlineColor[HINTON][1] = "black"; OutlineColor[HINTON][1] = "white"; break; } } real normColorValue(real x, real temp) { if (isNaN(x)) return x; if (x * temp > 10) return 1.0; else if (x * temp < -10) return 0.0; else return SIGMOID(x, temp); } char *getColor(real x, real temp, int palette) { x = normColorValue(x, temp); if (isNaN(x)) return NaNColor; return ColorMap[palette][(int)(x * (NUM_COLORS - 1))]; } flag setUnitTemp(real val) { if (Net) { Net->unitTemp = POW(2.0, val); updateUnitDisplay(); } return TCL_OK; } enum plotfieldtypes {NEXT, LNEXT, CNEXT, RNEXT, SPAN, UNITF, BLANK, FILL}; typedef struct plotField *PlotField; struct plotField { int type; int num; int width; int numUnits; Group group; Unit unit; PlotField next; }; static void freePlotFieldList(PlotField PF) { PlotField next; for (; PF; PF = next) { next = PF->next; free(PF); } } static int numUnplotted(PlotField PF, int needed) { int unused = 0; Group G = PF->group; FOR_EVERY_UNIT(G, { if (unused >= needed) break; if (U->plotCol == 0) { U->plotCol = -PF->num; unused++; } }); return unused; } static int spanUnplotted(PlotField PF) { int u, unused = 0; Group G = PF->group; for (u = PF->unit->num; u < G->numUnits && u < PF->unit->num + PF->width; u++) { if (G->unit[u].plotCol == 0) { G->unit[u].plotCol = -PF->num; unused++; } } return unused; } static int plotNext(PlotField PF, int offset) { int plotted = 0; Group G = PF->group; FOR_EVERY_UNIT(G, { if (plotted >= PF->numUnits) break; if (U->plotCol == -PF->num) { U->plotCol = offset + plotted++; U->plotRow = Net->plotRows; } }); return plotted; } static int plotSpan(PlotField PF, int offset) { int u, plotted = 0; Group G = PF->group; Unit U; for (u = PF->unit->num; u < G->numUnits && u < PF->width + PF->unit->num; u++) { U = G->unit + u; if (U->plotCol == -PF->num) { U->plotCol = offset + u - PF->unit->num; U->plotRow = Net->plotRows; plotted++; } } return plotted; } flag plotRow(int argc, char *argv[], int *unitsPlotted) { int arg, numFills = 0, numUnits, totalWidth = 0, fillSpace, numShort, numFields = 0; PlotField PF, first = NULL, last = NULL; Net->plotRows++; arg = 0; while (arg < argc) { numFields++; PF = (PlotField) safeCalloc(1, sizeof *PF, "plotRow:PF"); PF->num = numFields; if (last) last->next = PF; else first = PF; last = PF; switch (argv[arg++][0]) { case 'n': if (arg >= argc - 1) return warning("plotRow: missing fields"); PF->type = NEXT; if (!(PF->group = lookupGroup(argv[arg++]))) { freePlotFieldList(first); return warning("plotRow: group \"%s\" doesn't exist", argv[--arg]); } PF->width = PF->numUnits = numUnplotted(PF, atoi(argv[arg++])); break; case 'l': if (arg >= argc - 1) return warning("plotRow: missing fields"); PF->type = LNEXT; if (!(PF->group = lookupGroup(argv[arg++]))) { freePlotFieldList(first); return warning("plotRow: group \"%s\" doesn't exist", argv[--arg]); } if ((PF->width = atoi(argv[arg++])) < 0) { freePlotFieldList(first); return warning("plotRow: numUnits (%d) must be non-negative " "for group \"%s\"", PF->width, PF->group->name); } PF->numUnits = numUnplotted(PF, PF->width); break; case 'c': if (arg >= argc - 1) return warning("plotRow: missing fields"); PF->type = CNEXT; if (!(PF->group = lookupGroup(argv[arg++]))) { freePlotFieldList(first); return warning("plotRow: group \"%s\" doesn't exist", argv[--arg]); } if ((PF->width = atoi(argv[arg++])) < 0) { freePlotFieldList(first); return warning("plotRow: numUnits (%d) must be non-negative " "for group \"%s\"", PF->width, PF->group->name); } PF->numUnits = numUnplotted(PF, PF->width); break; case 'r': if (arg >= argc - 1) return warning("plotRow: missing fields"); PF->type = RNEXT; if (!(PF->group = lookupGroup(argv[arg++]))) { freePlotFieldList(first); return warning("plotRow: group \"%s\" doesn't exist", argv[--arg]); } if ((PF->width = atoi(argv[arg++])) < 0) { freePlotFieldList(first); return warning("plotRow: numUnits (%d) must be non-negative " "for group \"%s\"", PF->width, PF->group->name); } PF->numUnits = numUnplotted(PF, PF->width); break; case 's': if (arg >= argc - 2) return warning("plotRow: missing fields"); PF->type = SPAN; if (!(PF->group = lookupGroup(argv[arg++]))) { freePlotFieldList(first); return warning("plotRow: group \"%s\" doesn't exist", argv[--arg]); } PF->width = atoi(argv[arg++]); if (PF->width < 0 || PF->width >= PF->group->numUnits) { freePlotFieldList(first); return warning("plotRow: unit index %d of range in group \"%s\"", PF->width, PF->group->name); } PF->unit = PF->group->unit + PF->width; if ((PF->width = atoi(argv[arg++])) < 0) { freePlotFieldList(first); return warning("plotRow: numUnits (%d) must be non-negative " "for group \"%s\"", PF->width, PF->group->name); } PF->numUnits = spanUnplotted(PF); break; case 'u': if (arg >= argc) return warning("plotRow: missing fields"); PF->type = UNITF; if (!(PF->unit = lookupUnit(argv[arg++]))) { freePlotFieldList(first); return warning("plotRow: group \"%s\" doesn't exist", argv[--arg]); } PF->width = 1; PF->unit->plotCol = -PF->num; break; case 'b': if (arg >= argc) return warning("plotRow: missing fields"); PF->type = BLANK; if ((PF->width = atoi(argv[arg++])) < 0) { freePlotFieldList(first); return warning("plotRow: blank width (%d) must be non-negative", PF->width); } break; case 'f': PF->type = FILL; numFills++; break; default: return warning("plotRow: unrecognized command: \"%s\"", argv[--arg]); } totalWidth += PF->width; } if (totalWidth < Net->plotCols && numFills) { fillSpace = (Net->plotCols - totalWidth) / numFills; numShort = numFills - ((Net->plotCols - totalWidth) % numFills); for (PF = first; PF; PF = PF->next) if (PF->type == FILL) { if (numShort) { PF->width = fillSpace; numShort--; } else PF->width = fillSpace + 1; } } /* I now use totalWidth for the offset of each field */ for (PF = first, totalWidth = 1, numUnits = 0; PF; PF = PF->next) { switch (PF->type) { case NEXT: case LNEXT: numUnits += plotNext(PF, totalWidth); break; case CNEXT: numUnits += plotNext(PF, totalWidth + ((PF->width - PF->numUnits) / 2)); break; case RNEXT: numUnits += plotNext(PF, totalWidth + PF->width - PF->numUnits); break; case SPAN: numUnits += plotSpan(PF, totalWidth); break; case UNITF: /* It is important that this doesn't add 1 to numUnits */ PF->unit->plotCol = totalWidth; PF->unit->plotRow = Net->plotRows; break; case BLANK: case FILL: break; default: fatalError("plotRow: bad plotField type: %d", PF->type); } totalWidth += PF->width; } freePlotFieldList(first); *unitsPlotted = numUnits; return TCL_OK; } flag drawUnitsLater(void) { if (!UnitsNeedRedraw) { UnitsNeedRedraw = TRUE; Tcl_DoWhenIdle((Tcl_IdleProc *) drawUnits, NULL); } return TCL_OK; } flag drawUnits(ClientData junk) { int x, y; if (!UnitsNeedRedraw) return TCL_OK; UnitsNeedRedraw = FALSE; if (!UnitUp) return TCL_OK; if (!Net) { if (Tcl_Eval(Interp, ".unit.c.c delete all")) return TCL_ERROR; return updateUnitDisplay(); } fillPalette(Net->unitPalette); if (Net->unitCellSize < 5 || Net->unitCellSize > 100) return warning("drawUnits: unitCellSize (%d) must be in the range [5,100]", Net->unitCellSize); if (Net->unitCellSpacing < 0 || Net->unitCellSpacing > 100) return warning("drawUnits: unitCellSpacing (%d) must be in the range " "[0,100]", Net->unitCellSpacing); Space = Net->unitCellSize + Net->unitCellSpacing; if (Tcl_Eval(Interp, ".unit.c.c delete all")) return TCL_ERROR; PlotWidth = 0; FOR_EACH_GROUP(FOR_EVERY_UNIT(G, { if (U->plotCol > PlotWidth) PlotWidth = U->plotCol; })); if (!PlotWidth) return updateUnitDisplay(); /* Now it's the width of one epoch */ PlotWidth = (PlotWidth + 2) * Space; eval(".unit.c.c configure -scrollregion {0 0 %d %d}", PlotWidth, (Net->plotRows + 2) * Space); eval(".unit.c.c xview moveto 0; .unit.c.c yview moveto 0"); FOR_EACH_GROUP({ if (G->costType & ERROR_MASKS) { int outputShift; int outputSize; if (Net->unitCellSize <= 7) outputSize = Net->unitCellSize - 4; else if (Net->unitCellSize <= 14) outputSize = Net->unitCellSize - 6; else outputSize = Net->unitCellSize * OUTPUT_SCALE; if ((outputSize & 1) != (Net->unitCellSize & 1)) outputSize--; outputShift = (Net->unitCellSize - outputSize) / 2; FOR_EVERY_UNIT(G, { if (U->plotCol) { x = U->plotCol * Space; y = U->plotRow * Space; if (eval(".unit.c.c create canvrect %d %d %d %d %d %d -3 " "-fill %s -tag {cr %d:%d:t};" ".setUnitBindings %d:%d:t %d %d 1", x, y, x + Net->unitCellSize, y + Net->unitCellSize, G->num, U->num, NaNColor, G->num, U->num, G->num, U->num, G->num, U->num) != TCL_OK) return TCL_ERROR; x += outputShift; y += outputShift; if (eval(".unit.c.c create canvrect %d %d %d %d %d %d -2 " "-fill %s -tag {cr %d:%d:0};" ".setUnitBindings %d:%d:0 %d %d 0", x, y, x + outputSize, y + outputSize, G->num, U->num, NaNColor, G->num, U->num, G->num, U->num, G->num, U->num) != TCL_OK) return TCL_ERROR; } }); } else FOR_EVERY_UNIT(G, { if (U->plotCol) { x = U->plotCol * Space; y = U->plotRow * Space; if (eval(".unit.c.c create canvrect %d %d %d %d %d %d -1 " "-fill %s -width 1 -tag {cr %d:%d:0};" ".setUnitBindings %d:%d:0 %d %d 0", x, y, x + Net->unitCellSize, y + Net->unitCellSize, G->num, U->num, NaNColor, G->num, U->num, G->num, U->num, G->num, U->num) != TCL_OK) return TCL_ERROR; } }); }); if (eval(".setViewerSize %d %d", PlotWidth, Space * (Net->plotRows + 2))) return TCL_ERROR; if (eval(".unit.c.c configure -xscrollincrement %d -yscrollincrement %d", Space, Space)) return TCL_ERROR; return setUnitValue(Net->unitDisplayValue); } /* If number of columns is 0, it figures out a nice value */ flag autoPlot(int numCols) { int maxUnits, argc, unitsPlotted; char *argv[7]; if (numCols <= 0) { maxUnits = 0; numCols = 10; FOR_EACH_GROUP({ if (G->numColumns) { if (G->numColumns > numCols) numCols = G->numColumns; } else if (G->numUnits > maxUnits) maxUnits = G->numUnits; }); numCols = imax(numCols, CEIL(SQRT(5 * maxUnits))); } Net->plotCols = numCols; Net->plotRows = 0; FOR_EACH_GROUP(FOR_EVERY_UNIT(G, U->plotCol = U->plotRow = 0)); maxUnits = 0; FOR_EACH_GROUP_BACK({ if (G->type & BIAS) { argv[0] = "l"; argv[1] = G->name; sprintf(Buffer, "%d", numCols); argv[2] = Buffer; argc = 3; } else if (G->type & ELMAN) { Net->plotRows--; argv[0] = "b"; argv[1] = "2"; argv[2] = "f"; argv[3] = "c"; argv[4] = G->name; sprintf(Buffer, "%d", (G->numColumns > 0) ? G->numColumns : numCols); argv[5] = Buffer; argv[6] = "f"; argc = 7; } else { argv[0] = "f"; argv[1] = "c"; argv[2] = G->name; sprintf(Buffer, "%d", (G->numColumns > 0) ? G->numColumns : numCols); argv[3] = Buffer; argv[4] = "f"; argc = 5; } do { if (plotRow(argc, argv, &unitsPlotted)) return TCL_ERROR; } while (unitsPlotted > 0); }); Net->plotRows--; return drawUnitsLater(); } flag setUnitValue(int val) { /* Set the label */ if (eval("global _valueLabel; .unit.c.label configure " "-text $_valueLabel(%d)", val)) return TCL_ERROR; Net->unitDisplayValue = val; Tcl_UpdateLinkedVar(Interp, ".unitDisplayValue"); return updateUnitDisplay(); } static flag displayPipeExample(ExampleSet S) { eval(".unit.l.list delete 0 end"); if (!S->pipeExample) return warning("example set %s has no pipe example", S->name); if (S->pipeExample->name) eval(".unit.l.list insert end {%s}", S->pipeExample->name); else eval(".unit.l.list insert end {Pipe Example}"); return TCL_OK; } flag updateUnitDisplay(void) { int tpi, event, eventStart, eventStop; ExampleSet S; if (!UnitUp || UnitsNeedRedraw) return TCL_OK; if (!Net || !Net->currentExample) { eval(".unit.t.left3 configure -state disabled;" ".unit.t.left2 configure -state disabled;" ".unit.t.left configure -state disabled;" ".unit.t.left0 configure -state disabled;" ".unit.t.right0 configure -state disabled;" ".unit.t.right configure -state disabled;" ".unit.t.right2 configure -state disabled;" ".unit.t.right3 configure -state disabled;" ".unit.t.step2 configure -state disabled;" ".unit.t.step3 configure -state disabled;" ".unit.t.event configure -state disabled;" ".unit.t.tick configure -state disabled;" ".unit.t.etick configure -state disabled;"); eval("set .viewEvent {};" "set .viewEvents {};" "set .viewTime {};" "set .viewMaxTime {};" "set .viewEventTime {};" "set .viewMaxEventTime {};" ".setUnitEntries;"); return eval(".unit.c.c itemconfigure all -stipple {}"); } S = Net->currentExample->set; tpi = Net->ticksPerInterval; ViewTick = imax(ViewTick, 0); ViewTick = imin(ViewTick, Net->ticksOnExample - 1); event = Net->eventHistory[ViewTick]; if (eval(".unit.c.c delete hint") != TCL_OK) return TCL_ERROR; if (eval(".unit.c.c itemconfigure cr -stipple {}") != TCL_OK) return TCL_ERROR; if ((Net->unitDisplaySet == TRAIN_SET && S == Net->trainingSet) || (Net->unitDisplaySet == TEST_SET && S == Net->testingSet)) { if (S->mode == PIPE && displayPipeExample(S)) return TCL_ERROR; if (eval(".unit.l.list selection clear 0 end; .unit.l.list see %d; " ".unit.l.list activate %d; .unit.l.list selection set active;", Net->currentExample->num, Net->currentExample->num)) return TCL_ERROR; } else eval(".unit.l.list selection clear 0 end"); for (eventStart = 0; Net->eventHistory[eventStart] < event; eventStart++); for (eventStop = eventStart; eventStop < Net->ticksOnExample && Net->eventHistory[eventStop] == event; eventStop++); if (event >= 0) eval("set .viewEvent %d", event); else eval("set .viewEvent {}"); eval("set .viewEvents %d", Net->currentExample->numEvents); eval("set .viewTime %d:%d", (ViewTick + 1) / tpi, (ViewTick + 1) % tpi); eval("set .viewMaxTime %d:%d", Net->ticksOnExample / tpi, Net->ticksOnExample % tpi); eval("set .viewEventTime %d:%d", (ViewTick - eventStart + 1) / tpi, (ViewTick - eventStart + 1) % tpi); eval("set .viewMaxEventTime %d:%d", (eventStop - eventStart) / tpi, (eventStop - eventStart) % tpi); eval(".setUnitEntries"); eval(".unit.t.event configure -state normal;" ".unit.t.tick configure -state normal;" ".unit.t.etick configure -state normal;"); if (ViewTick <= 0 || !Net->currentExample) eval(".unit.t.left3 configure -state disabled;" ".unit.t.left2 configure -state disabled;" ".unit.t.left configure -state disabled;"); else eval(".unit.t.left3 configure -state normal;" ".unit.t.left2 configure -state normal;" ".unit.t.left configure -state normal"); if (ViewTick >= Net->ticksOnExample - 1 || !Net->currentExample) eval(".unit.t.step3 configure -state disabled;" ".unit.t.step2 configure -state disabled;" ".unit.t.right3 configure -state disabled;" ".unit.t.right2 configure -state disabled;" ".unit.t.right configure -state disabled;"); else eval(".unit.t.step3 configure -state normal;" ".unit.t.step2 configure -state normal;" ".unit.t.right3 configure -state normal;" ".unit.t.right2 configure -state normal;" ".unit.t.right configure -state normal"); eval(".updateUnitInfo"); eval("update idletasks"); return TCL_OK; } flag chooseUnitSet(void) { if (!Net) return loadExampleDisplay(); if (Net->unitDisplaySet == TRAIN_SET && !Net->trainingSet) Net->unitDisplaySet = NO_SET; else if (Net->unitDisplaySet == TEST_SET && !Net->testingSet) Net->unitDisplaySet = NO_SET; if (Net->unitDisplaySet == NO_SET) { if (Net->trainingSet) Net->unitDisplaySet = TRAIN_SET; else if (Net->testingSet) Net->unitDisplaySet = TEST_SET; } if (Net->unitDisplaySet == NO_SET) eval(".unit.l.label configure -text {}"); else eval(".unit.l.label configure -text $_unitSetLabel(%d)", Net->unitDisplaySet); return loadExampleDisplay(); } flag loadExampleDisplay(void) { int i; ExampleSet S = NULL; if (!UnitUp) return TCL_OK; eval(".unit.l.list delete 0 end"); if (!Net) return TCL_OK; if (Net->unitDisplaySet == TRAIN_SET) S = Net->trainingSet; else if (Net->unitDisplaySet == TEST_SET) S = Net->testingSet; else S = NULL; if (!S) return TCL_OK; for (i = 0; i < S->numExamples; i++) { if (S->example[i]->name) eval(".unit.l.list insert end {%s}", S->example[i]->name); else eval(".unit.l.list insert end %d", S->example[i]->num); } return TCL_OK; } /*****************************************************************************/ flag setLinkTemp(real val) { if (Net) { Net->linkTemp = POW(2.0, val); updateLinkDisplay(); } return TCL_OK; } flag setLinkValue(int val) { /* Set the label */ if (eval("global _valueLabel; .link.c.label configure " "-text $_valueLabel(%d)", val)) return TCL_ERROR; Net->linkDisplayValue = val; Tcl_UpdateLinkedVar(Interp, ".linkDisplayValue"); return updateLinkDisplay(); } flag drawLinksLater(void) { if (!LinksNeedRedraw) { LinksNeedRedraw = TRUE; Tcl_DoWhenIdle((Tcl_IdleProc *) drawLinks, NULL); } return TCL_OK; } flag drawLinks(ClientData junk) { int l, topmargin, leftmargin, fontsize, longestname = 0, inPos, outPos, Space, x, y; flag halted; Unit U, sU, P, sP; if (!LinksNeedRedraw) return TCL_OK; LinksNeedRedraw = FALSE; if (!LinkUp) return TCL_OK; if (!Net) return Tcl_Eval(Interp, ".link.c.c delete all"); fillPalette(Net->linkPalette); if (Net->linkCellSize < 2 || Net->linkCellSize > 100) return warning("drawLinks: linkCellSize (%d) must be in the range [2,100]", Net->linkCellSize); if (Net->linkCellSpacing < 0 || Net->linkCellSpacing > 100) return warning("drawLinks: linkCellSpacing (%d) must be in the range " "[0,100]", Net->linkCellSpacing); /* This should make another call to drawLinks */ if (Tcl_Eval(Interp, ".link.c.c delete all")) return TCL_ERROR; startTask(BUILDING_LINKS); eval(".buildLinkGroupMenus"); /* First go through and mark inPositions and mark groups that will have outgoing links to plot */ FOR_EACH_GROUP(G->outPosition = G->inPosition = -1); inPos = 0; FOR_EACH_GROUP_BACK({ if (!G->showIncoming || !G->numIncoming) continue; FOR_EVERY_UNIT(G, { FOR_EACH_BLOCK(U, { for (P = B->unit, sP = P + B->numUnits; P < sP; P++) { if (P->group->showOutgoing) { if (P->group->outPosition == -1) { P->group->outPosition = 0; if (strlen(P->group->name) > longestname) longestname = strlen(P->group->name); } if (G->inPosition == -1) { G->inPosition = inPos; inPos += G->numUnits + 1; } } } }); }); }); outPos = 0; FOR_EACH_GROUP_BACK({ if (G->outPosition != -1) { G->outPosition = outPos; outPos += G->numUnits + 1; } }); fontsize = imax(imin(Net->linkCellSize + 2, 18), 8); leftmargin = (fontsize * (longestname + 5)) * .7; topmargin = fontsize * 5; Space = Net->linkCellSize + Net->linkCellSpacing; eval("catch {font delete .link.font}; font create .link.font " "-family helvetica -size -%d -weight bold", fontsize); eval(".link.c.c configure -scrollregion {0 0 %d %d}\n", leftmargin + inPos * Space, topmargin + outPos * Space); eval(".link.c.c xview moveto 0; .link.c.c yview moveto 0"); halted = FALSE; FOR_EACH_GROUP({ if (halted) break; if (G->outPosition != -1) { eval(".link.c.c create text %d %d -text {%s} -anchor e " "-font .link.font", leftmargin - fontsize * 3, topmargin + (int)(((real) G->numUnits / 2 + G->outPosition) * Space), G->name); for (U = G->unit, sU = U + G->numUnits; U < sU; U += 5) eval(".link.c.c create text %d %d -text %d -anchor ne " "-font .link.font", leftmargin - 4, topmargin + (G->outPosition + U->num) * Space, U->num); } if (G->inPosition != -1) { eval(".link.c.c create text %d %d -text {%s} -anchor s " "-font .link.font", leftmargin + (int) (((real) G->numUnits / 2 + G->inPosition) * Space), topmargin - (int) (fontsize * 2), G->name); FOR_EVERY_UNIT(G, { l = 0; FOR_EACH_BLOCK(U, { for (P = B->unit, sP = P + B->numUnits; P < sP; P++, l++) { if (P->group->outPosition != -1) { x = leftmargin + (G->inPosition + U->num) * Space; y = topmargin + (P->group->outPosition + P->num) * Space; if (eval("set .r [.link.c.c create canvrect %d %d %d %d " "%d %d %d -fill %s -tag {cr %d:%d:%d}];" ".setLinkBindings %d:%d:%d %d %d %d %d %d", x, y, x + Net->linkCellSize, y + Net->linkCellSize, G->num, U->num, l, NaNColor, G->num, U->num, l, G->num, U->num, l, P->group->num, P->num, U->group->num, U->num, l) != TCL_OK) { stopTask(BUILDING_LINKS); return TCL_ERROR; } } } }); if ((U->num % 5) == 0) { eval(".link.c.c create text %d %d -text %d -anchor sw " "-font .link.font", leftmargin + (G->inPosition + U->num) * Space, topmargin - 2, U->num); } if ((halted = smartUpdate(FALSE))) break; }); } }); stopTask(BUILDING_LINKS); setLinkValue(Net->linkDisplayValue); return updateLinkDisplay(); } flag updateLinkDisplay(void) { int value = Net->linkDisplayValue, i, si, n = 0; Link L; Link2 M; real v, av; real mean = 0.0; real meanAbs = 0.0; real var = 0.0; /* real varAbs = 0.0;*/ real max = 0.0; real maxAbs = 0.0; real avgRange = 0.0; if (!LinkUp || LinksNeedRedraw) return TCL_OK; if (unsafeToRun("", BUILDING_LINKS)) return TCL_OK; if (eval(".link.c.c delete hint") != TCL_OK) return TCL_ERROR; if (eval(".link.c.c itemconfigure cr -stipple {}") != TCL_OK) return TCL_ERROR; FOR_EACH_GROUP({ if (G->inPosition != -1) { FOR_EVERY_UNIT(G, { L = U->incoming; M = U->incoming2; i = 0; FOR_EACH_BLOCK(U, { if (B->unit[0].group->outPosition != -1) { for (si = i + B->numUnits; i < si; i++) { switch (value) { case UV_LINK_WEIGHTS: v = L[i].weight; break; case UV_LINK_DERIVS: v = L[i].deriv; break; case UV_LINK_DELTAS: v = M[i].lastWeightDelta; break; default: return warning("updateLinkDisplay called with bad " "Net->linkDisplayValue"); } mean += v; av = (real) ABS(v); meanAbs += av; if (av > maxAbs) { maxAbs = av; max = v; } n++; } } else i += B->numUnits; }); }); } }); if (n) { mean /= n; meanAbs /= n; } FOR_EACH_GROUP({ if (G->inPosition != -1) { FOR_EVERY_UNIT(G, { L = U->incoming; M = U->incoming2; i = 0; FOR_EACH_BLOCK(U, { if (B->unit[0].group->outPosition != -1) { for (si = i + B->numUnits; i < si; i++) { switch (value) { case UV_LINK_WEIGHTS: v = L[i].weight; break; case UV_LINK_DERIVS: v = L[i].deriv; break; case UV_LINK_DELTAS: v = M[i].lastWeightDelta; break; default: return warning("updateLinkDisplay called with bad " "Net->linkDisplayValue"); } av = (real) ABS(v); avgRange += ABS(v - mean); var += SQUARE(v - mean); /* varAbs += SQUARE(v - meanAbs);*/ } } else i += B->numUnits; }); }); } }); if (n > 1) { avgRange /= n; var /= (n - 1); /* varAbs /= (n - 1);*/ } else { var = 0.0; /* varAbs = 0.0; */ } eval("set .linkMean %f", mean); eval("set .linkVar %f", var); eval("set .linkMAbs %f", meanAbs); eval("set .linkMDist %f", avgRange); eval("set .linkMax %f", max); eval(".updateLinkInfo"); eval("update idletasks"); return TCL_OK; } flag linksChanged(void) { if (updateUnitDisplay()) return TCL_ERROR; return drawLinksLater(); } flag buildLinkGroupMenus(void) { return eval(".buildLinkGroupMenus"); } void updateDisplays(mask update) { if (!Net) return; if (UnitUp && Net->unitUpdates & update) updateUnitDisplay(); if (LinkUp && Net->linkUpdates & update) updateLinkDisplay(); updateGraphs(update); }