Skip to content

Latest commit

 

History

History
894 lines (752 loc) · 46.1 KB

File metadata and controls

894 lines (752 loc) · 46.1 KB

Changelog

All notable changes to this project are documented in this file.

[3.6] – May 26, 2026

New Features

  • UCINET DL export (#237):

    • New Network → Export → DL… action writes the current graph to a UCINET DL file in FULLMATRIX DIAGONAL PRESENT format.
    • Multi-relation graphs are fully supported: all relations are written as consecutive matrices in the DATA: section under a single NM=k header (no file-level separator needed — the parser already advances its relation counter when the source row counter exceeds N).
    • Node labels are exported in ROW LABELS / COLUMN LABELS sections, enabling label-preserving roundtrip.
    • FileType::UCINET added to m_graphFileFormatExportSupported; the CLI io_roundtrip kernel now exercises the format automatically. Two existing baselines (Bernard_Killworth_Fraternity__FT5, StokmanZiegler_Netherlands__FT5) updated from performed: false to performed: true, equivalent: true.
  • Edge List export — weighted and simple (#238):

    • New Network → Export → List… action writes the active relation as a space-separated edge list file.
    • When the graph is weighted the user is asked whether to include weights: Yessource target weight per line (.wlst), Nosource target per line (.lst).
    • Node labels are used as identifiers; spaces in labels are replaced with underscores to keep the delimiter unambiguous.
    • A warning is shown when multiple relations are present (only the active relation is written).
    • Both FileType::EDGELIST_WEIGHTED and FileType::EDGELIST_SIMPLE added to the supported export list; three Tiny edge-list io_roundtrip baselines show performed: true, equivalent: true.
  • GraphViz DOT export with full roundtrip (#236):

    • New File → Export → GraphViz DOT… action writes a .dot file for the active relation (DOT has no native multi-relation concept; a warning is shown when more than one relation is present).
    • Export preserves: node label, color, shape, canvas coordinates (pos="x,y" — compatible with neato/fdp), and all custom node/edge attributes as DOT key=value pairs.
    • Edge weight, label, color, and custom attributes are written per edge. Undirected graphs suppress the reverse half of each symmetric pair.
    • Parser extended to read back everything that is written: readDotProperties now returns unknown attributes as a QHash<QString,QString> rather than discarding them; pos= is converted to node canvas coordinates; graph name quote-stripping fixes the roundtrip for quoted identifiers (digraph "Name" { … }).
    • FileType::GRAPHVIZ added to the supported export list so the CLI io_roundtrip regression kernel exercises the format automatically.
  • Subgraph save format expansion (#220):

    • The Save Subgraph As… dialog (reached via Edit → Subgraphs → Save visible / Save selected) now offers all seven supported export formats: GraphML, Pajek, Adjacency, GraphViz DOT, UCINET DL, Weighted Edge List, and Simple Edge List.
    • Format-aware fidelity warnings fire automatically before writing:
      • Custom node/edge attributes: a confirmation prompt is shown for any format that cannot preserve them (all formats except GraphML and DOT).
      • Single-relation-only formats (Adjacency, DOT, both Edge List variants) show an info notice when the subgraph has more than one relation.
    • Previously the dialog only offered GraphML, Pajek, and Adjacency.
  • Subgraph extraction (#218):

    • New Edit → Subgraphs submenu with two actions:
      • Save visible nodes as subgraph… — extracts all nodes currently visible on the canvas (i.e. not hidden by any filter) and the edges that run between them into an independent graph file. Always enabled when a network is loaded.
      • Save selected nodes as subgraph… — extracts the currently selected nodes and their inter-edges. Enabled when at least one node is selected.
    • Both actions prompt for a network name, pre-fill the save dialog filename from that name, and save to GraphML (which preserves all custom attributes and relations).
    • Vertices are renumbered from 1 in the extracted graph; all visual properties, custom node/edge attributes, and multi-relation structure are preserved.
    • Original graph remains unchanged (non-destructive).
  • Compound AND-logic query filter (#221):

    • New Filter → Filter by Query… action (Ctrl+X, Ctrl+B) opens the Query Builder dialog — a dynamic multi-condition filter composer that supports both nodes and edges.
    • The user picks a scope (Nodes or Edges), then adds one or more condition rows. Each row specifies an attribute key, an operator (=, ≠, >, <, ≥, ≤, contains), and a value. All rows are ANDed: only nodes/edges that satisfy every condition are kept visible.
    • Rows can be added ("+ Add condition" button) or removed (per-row "−" button; the last row's remove button disables itself automatically). The attribute key combo is populated from the graph's current node or edge attribute keys and is also freely editable.
    • Applies the same non-destructive snapshot/restore mechanism as all other filters: the result appears as a chip in the filter bar and can be individually removed or cleared with Restore All.
    • Numeric comparisons (>, <, ≥, ≤) automatically downcast to double when both sides are valid numbers; string comparisons fall back to case-insensitive lexicographic order; "contains" is always case-insensitive substring search.
  • Connected components count and color-by-component layout (#85):

    • Analyze → Cohesion → Connectedness now reports the number of weakly connected components when the network is disconnected, alongside a hint pointing to the new colorize action.

    • New Layout → Node Color by Connected Component (Ctrl+L, Ctrl+C, Ctrl+0) colors every node by its weakly connected component: nodes in the same component share the same color, making isolated sub-networks immediately visible. Up to 15 visually distinct palette colors are used; the palette cycles for networks with more components. If the network is already fully connected the action reports "one component" and leaves colors unchanged.

    • Both directed and undirected networks are supported. Weak connectivity is used throughout: two nodes are in the same component when there is an undirected path between them (edge directions are ignored). This is consistent with Gephi, igraph, and NetworkX defaults and answers the practical "how many disconnected islands?" question for both graph types. Strong connectivity (all-pairs directed reachability) remains available via the SSSP engine.

    • Graph::graphWeaklyConnectedComponents() implements the BFS, caches the count in m_graphWeaklyConnectedComponents and per-node component IDs in m_vertexComponentId. Cache is invalidated whenever the graph is structurally modified (same trigger as distances / centralities).

    • Connectivity semantics — what the app computes and reports:

      Graph type Topology Components Connected? UI message
      Undirected All nodes reachable 1 yes "connected (1 component)"
      Undirected Isolated sub-networks >1 no "disconnected (N components)"
      Directed Every pair has a directed path 1 yes "weakly connected (1 component)"
      Directed A→B only, not B→A 1 yes "weakly connected (1 component)" — one island, not strongly connected
      Directed Two separate islands >1 no "disconnected (N weakly connected components)"

      The "connected" determination uses weak connectivity (components == 1) throughout, for both directed and undirected networks. Weak connectivity ignores edge direction and answers the practical "how many disconnected islands?" question consistently. Strong connectivity (all-pairs directed reachability) is a separate, stricter property available via the geodesic distances computation.

  • Clustering Coefficient added to node color layout (#37):

    • Layout → Node Color by prominence index → Clustering Coefficient (Ctrl+L, Ctrl+C, Ctrl+G) colors nodes by their local Watts-Strogatz clustering coefficient using the same blue→red gradient as all other prominence indices: nodes with higher clustering are warmer (red), lower clustering are cooler (blue).
    • Fully integrated at the same depth as the 12 existing centrality/prestige indices: appears in the Layout control panel combo, the analysis prominence combo, Filter Nodes by Centrality (filter and find by CLC threshold), and the prominence distribution chart.
    • IndexType::CLC = 13 added to the index enum; clusteringCoefficient() now builds the discreteCLCs distribution map for charting.
  • Zero-weight edge display settings (#30):

    • New Settings → Edges → Show zero-weight edges checkbox (default: on): when unchecked, zero-weight edges are silently skipped on load — no ghost edges, no artifacts. The Zero valued edge color picker is automatically disabled when the checkbox is off.
    • Zero-weight edge color is now user-configurable: the hardcoded "blue" is replaced by initEdgeColorZero, driven by the existing Settings → Edges → Zero valued edge color picker which was already present but disconnected from edgeCreate().
  • Configurable edge arrow size (#32):

    • New Settings → Edges → Arrow size spinbox (range 2–20, default 6) lets the user control the size of arrowheads on directed edges.
    • The change applies to all edges on the canvas immediately and is persisted for future sessions.

Improvements

  • SSSP parallelisation — major performance boost for large networks (#241, #242):

    • All shortest-path computations (distances, betweenness centrality, stress centrality, closeness, eccentricity, power centrality) now run concurrently across all available CPU cores via QtConcurrent::blockingMap.

    • Phase 1 (#241): per-source SSSP scratch state (BFS stack, predecessor lists, dependency accumulators, distance and sigma arrays, nth-order neighbourhood map) was extracted from Graph and GraphVertex into a self-contained PerSourceScratch struct. Replacing per-edge QHash lookups with contiguous QVector index reads improved cache locality and gave an immediate 14–23% speedup even on a single thread.

    • Phase 2 (#242): the source loop in DistanceEngine::runAllSources() is now distributed across all CPU cores. Each worker thread owns a ThreadLocalState holding its own PerSourceScratch, partial BC/SC accumulator arrays, and running totals for graph-wide aggregates. A single-threaded reduction step after the loop merges everything into graph state with zero contention. APSP write-back is race-free without any mutex because each source vertex is processed by exactly one thread.

    • Measured speedup (Debug build, 24-core Linux):

      Network Centralities Before After Speedup
      BA directed N=500 E=1219 ON 679 ms 255 ms 2.7×
      N=1000 A=10000 OFF 28 423 ms 3 431 ms 8.3×
      N=1000 A=10000 ON 47 020 ms 5 949 ms 7.9×

      Speedup scales near-linearly with core count because sources are fully independent once per-source scratch state is thread-local.

    • All 36 golden regression baselines pass; numeric results are bit-for-bit identical to the sequential implementation.

  • Canvas rendering performance for large networks (#180, #240):

    • The dominant bottleneck on large networks (2000+ nodes, 40000+ edges) was QGraphicsScene::BspTreeIndex (the previous default): every prepareGeometryChange() call — triggered O(E) times per rubber-band drag or CTRL+A — paid an O(log N) BSP tree update. Result: selection and drag were nearly unresponsive on large networks.
    • Scene index now defaults to NoIndex, eliminating BSP overhead entirely. Rubber-band drag, CTRL+A, and full-network moves are now fast on large networks. Memory consumption is also reduced since the BSP tree structure is not built.
    • Existing users are migrated automatically on first launch (settingsMigration = 2); the setting remains user-controllable via Settings → Canvas → Scene index method.
    • QPen and QBrush objects in GraphicsEdge and GraphicsNode are now cached and rebuilt only on property changes, avoiding per-paint() heap allocations.
    • Nine bulk visibility-toggle methods (setNodeLabelsVisibility, setEdgeArrowSize, setEdgeHighlighting, etc.) now wrap their loops with viewport()->setUpdatesEnabled(false/true), coalescing per-item update() calls into a single viewport repaint.
    • scene()->items() loops replaced with direct edgesHash/nodeHash iteration in setEdgeOffsetFromNode and setAllItemsVisibility.
    • Hot-path qDebug calls removed from handleSelectionChanged, selectedNodes, and selectedEdges (fired on every selection event).
  • UI declutter & UX improvements (#234):

    • Removed the two "Apply" buttons from the Layout section of the Control Panel. All three layout comboboxes (Prominence Index, Type, Force-Directed Model) now apply immediately on selection change, with no extra click required.
    • Layout Type defaults to "None" (was "Radial") so opening the panel no longer implies a radial layout is pending.
    • Mutual exclusion enforced between By-Prominence-Index (Radial/Level types) and Force-Directed Model: selecting a force-directed model resets the Type to None, and vice versa.
    • Toolbar filter actions regrouped: node-filter icons sit alongside other node actions; edge-filter icons sit alongside edge actions.
    • Node Properties and Edge Properties toolbar actions are now selection-aware: nothing selected → status-bar hint; exactly one node/edge → single-item dialog; multiple selected → bulk-edit dialog.
    • Statistics Panel sectioned into five collapsible groups (▾/▴ toggle): NETWORK, SELECTION, CLICKED NODE, CLICKED EDGE, DISTRIBUTION. Each section collapses and expands independently.
    • In-Degree/Out-Degree rows in the Clicked Node section and Weight/Reciprocal rows in the Clicked Edge section auto-hide until a node or edge is clicked.
    • Left Control Panel wrapped in a scroll area: when the Data Table dock reduces available vertical space the panel scrolls rather than overlapping its widgets.
  • Better feedback during long operations: the status bar now shows a "Computing … Please wait…" message for every analysis and layout operation that can take noticeable time (centrality measures, prestige indices, matrix computations, structural equivalence, force-directed and prominence-index layouts, and more). The message is painted to the screen immediately, so users always know the app is working.

Bug Fixes

  • UCINET DL two-mode networks now load correctly (#63): three bugs in parser_dl.cpp caused two-mode (NR × NC affiliation) files to silently produce wrong node counts, wrong node numbers, and misrouted labels. Fixed: (1) totalNodes is now set to NR + NC when two-mode is detected; (2) row and col nodes are created with explicit sequential numbers (1..NR and NR+1..NR+NC) instead of a broken auto-numbered batch; (3) COL LABELS: is recognised as an alias for COLUMN LABELS:. Two golden IO-roundtrip baselines added (TinyDL_TwoMode_3x3_labeled, TinyDL_TwoMode_3x3_nolabels). Note: UCINET two-mode files always load as a bipartite directed graph in SocNetV (directed edges from mode-1 row nodes to mode-2 column nodes). Projection to person-network or event-network is not yet supported for the DL format; it is tracked as a separate feature request.

  • Galaskiewicz famous network now loads correctly (#15): the .2sm data file was missing from data.qrc, so writeFamousNetwork() returned early with an empty temp file — causing "no data rows found" for all three import modes. Added the resource entry and removed the now-dead hardcoded data rows from graph_reports.cpp.

  • Edge mode now follows relation switches (#53): switching to a different relation now restores that relation's directed/undirected state. Each relation tracks its own flag in m_relationsDirected; relationSet() saves the departing state and restores the incoming one, recomputes m_graphIsSymmetric from actual edges, and emits signalGraphDirectedChanged so the edge-mode combo and the arrows action in the toolbar update without mutating any edges.

  • Zero-weight edges: five pre-existing computation bugs fixed (#30):

    • outEdgesCount() now skips weight-0 edges → density no longer overcounted.
    • graphReciprocity() now skips weight-0 edges, preventing a false edgeExists(v2,v1)==0 match against absent reverse edges that inflated the reciprocated-ties count and could produce a 0/0 arc-reciprocity ratio.
    • clusteringCoefficientLocal() now excludes weight-0 neighbours from the neighbourhood k, keeping the k*(k−1) denominator correct.
    • BFS (bfsSSSP) now skips weight-0 edges so they are not traversed as valid 1-hop connections (affected geodesic distances, reachability, and all BFS-derived centralities).
    • Dijkstra (dijkstraSSSP) now skips weight-0 edges, preventing free paths (dist_w = dist_u + 0) and a division-by-zero crash when inverseWeights is enabled (1/0 = ∞).
  • Canvas: Shift+click now adds a node to the current selection (#235): Shift+left-clicking a node toggles it into or out of the selection without clearing previously selected nodes. Qt's item-level mouse handler in RubberBandDrag mode only treats Ctrl as additive; the fix intercepts Shift+LeftButton in GraphicsWidget::mousePressEvent and calls node->setSelected(!node->isSelected()) directly, bypassing Qt's default clear-and-select path. Shift+click on empty canvas space (rubber- band extension) and plain click behaviour are unchanged.

  • DOT parser: self-contained graph [...] block skips next node (#236 follow-up): when our exporter writes graph [label="Name"]; on a single line, the parser was entering multi-line netProperties mode and then treating the very next node declaration as the block terminator, silently discarding it. The skipped node was re-created with its DOT identifier as label ("n1" instead of "1") when the first edge statement was processed, producing wrong edge endpoints in the reloaded graph. Fix: only enter multi-line mode when ] is absent from the graph [ line. All three TinyGraphviz DOT io_roundtrip tests now show ROUNDTRIP_EQUIV=1.

  • Multi-relation graph incorrectly reported as non-weighted (#236 follow-up): isWeighted() correctly scans only the current relation (fixed in #82). However, the io_roundtrip regression kernel queried isWeighted() after iterating all relations and restoring to relation 0, so a graph whose relation 0 is binary but relation 1 is weighted was reported as weighted: false. Added Graph::isAnyRelationWeighted(), which checks every relation, and updated the kernel to use it for the graph.weighted JSON field.

  • Keyboard shortcut conflicts resolved:

    • Ctrl+T (Data Table toggle) conflicted with the Ctrl+T, Ctrl+* prefix used by all four Structural Equivalence analysis actions — those sequences were silently unreachable on every platform. Data Table is now Ctrl+D.
    • Ctrl+X, Ctrl+S (Focus on Selection filter, WS9) duplicated the pre-existing Ctrl+X, Ctrl+S shortcut for "Selected nodes → Star" subgraph operation. Focus on Selection is now Ctrl+X, Ctrl+O.
    • Ctrl+X, Ctrl+Q (Query Builder filter) mapped to ⌘+Q on macOS — the system-level Quit — when used as the second chord of a sequence. Query Builder is now Ctrl+X, Ctrl+B.
    • Duplicate Ctrl+Shift+Left/Right shortcuts removed from the rotate toolbar buttons (the menu actions already own those sequences).
  • Bezier curve edges now work (#149): the Options → Edges → Bezier Curves toggle was present but non-functional. Fixed and fully implemented: edges now draw as smooth quadratic arcs, arrowheads follow the curve tangent at each endpoint (including on reciprocated edges), the lens-shaped fill artifact is gone, new edges drawn while the toggle is on are born as curves, and the setting persists across sessions.

[3.5] – May 8, 2026

New Features

  • Graph exploration filters (WS9):

    • Focus on Node (Ego Network): hides all nodes except the selected node and its direct neighbors, and all non-incident edges. Available in the Filter menu and node right-click context menu (#211).
    • Focus on Selection: hides all nodes not in the current selection and all edges whose endpoints are not both selected. Action Ctrl+X, Ctrl+S; available in Filter menu and node right-click context menu (#210).
    • Restore All Nodes: restores all nodes hidden by any filter. Available in Filter menu and node right-click context menu.
    • Restore All Edges: re-enables all edges hidden by the weight filter. Action Ctrl+E, Ctrl+R; available in the Filter menu (#213).
    • All node-visibility filters (ego network, selection, centrality) now share a unified non-destructive snapshot/restore history stack — Restore All works across all filter types (#216).
  • Ego-centered radial layout: places a selected node at the canvas center, its 1-hop out-neighbors on an inner ring, and all remaining nodes on an outer ring. Available via Layout menu (Ctrl+Alt+E) and node right-click context menu (#214).

  • Node/edge attribute system (#224):

    • Single-key node attribute API: Graph::vertexCustomAttributeSet() / vertexCustomAttributeRemove().
    • Edge custom attribute storage: GraphVertex::m_outEdgeCustomAttributes, Graph::edgeCustomAttributesSet() / edgeCustomAttributes().
    • Edge Properties dialog (DialogEdgeEdit): edit label, weight, color and arbitrary custom key/value pairs; accessible from the toolbar and edge right-click context menu.
    • GraphML roundtrip for edge custom attributes: unique keys exported as d2000+ <key for="edge"> definitions; per-edge <data> tags written on save and parsed back on load.
    • Filter Nodes By Attribute: Graph::vertexFilterByAttribute(key, value) — non-destructive snapshot/restore filter; available in the Filter menu (Ctrl+X, Ctrl+A).
  • Attribute-based filtering (#217):

    • FilterCondition struct: scope (Nodes/Edges/Both), key, operator (= > < contains), value; label() for future filter bar chips.
    • DialogFilterByAttribute: scope selector, editable key combo populated from the graph's existing node/edge attribute keys, operator dropdown, free-text value field.
    • Graph::vertexFilterByAttribute(FilterCondition): refactored to accept the full condition struct; numeric-aware comparison (tries toDouble(), falls back to lexicographic).
    • Graph::edgeFilterByAttribute(FilterCondition): hides edges not matching the condition; uses the same snapshot/restore stack as node filters.
    • Filter combo added to the Control Panel (Network group) for one-click access to all filter actions.
    • Dedicated toolbar filter group with distinct icons for each filter action.
  • Filter bar with chips (#219):

    • Persistent FilterBarWidget strip between toolbar and canvas; hidden when no filter is active, auto-shows when any filter is applied.
    • Each active filter condition appears as a labelled chip (e.g. Nodes: ego network, Edges: weight filter, Nodes: type = investor).
    • ×-close on the most recently applied chip removes it and pops one entry from the snapshot/restore stack. Earlier chips show a disabled × with a tooltip explaining the order constraint.
    • "Clear all" button drains the full node filter stack and resets the edge filter in one click.
    • All five filter actions emit chips: centrality, ego network, selection, attribute (Nodes/Edges/Both), and edge weight filter.
    • Bar stays in sync when filters are removed via menu or toolbar actions.
  • Node/edge data table dock (#225):

    • New GraphTableWidget dockable panel (Ctrl+T, Options menu and Edit menu) with two tabs — Nodes and Edges — each backed by a QAbstractTableModel cache.
    • Node tab: fixed columns (#, Label, Visible, Shape, Size, Color) plus one column per custom attribute key. Label, Size, Color and custom attribute cells are inline-editable (double-click); #, Visible, Shape are read-only and rendered with a muted background.
    • Edge tab: fixed columns (Source, Target, Relation, Weight, Label, Color) plus custom attrs. Weight, Label, Color and custom attribute cells are editable; Source, Target, Relation are read-only and shaded.
    • All edits write back to the graph immediately via the Graph API.
    • Live search bar filters all columns (case-insensitive); column headers are sortable; a Refresh button reloads data from the current graph.
    • Panel auto-refreshes on file load and graph reset when it is open.
    • Action now has a dedicated data_table_48px.svg icon.
  • Structured CSV/JSON export (#226):

    • TableExport::toCSV() and TableExport::toJSON() free functions (src/graph/io/table_export.*) — QtCore only, no UI dependency.
    • Each tab in the Data Table dock gains Export CSV and Export JSON buttons; they export the currently visible (search-filtered) rows so what you see is what you get. Tooltip makes the scope explicit.
    • Network → Export to other... gains four new actions: Nodes as CSV, Edges as CSV, Nodes as JSON, Edges as JSON — these always export all rows regardless of any active search filter.
    • Status bar reports the export path on success.
  • Structured CSV/JSON attribute import (#227, refs #169):

    • TableImport::fromCSV() and TableImport::fromJSON() free functions (src/graph/io/table_import.*) — RFC 4180 CSV parser and JSON array-of-objects parser; QtCore only, no UI dependency.
    • DialogImportAttributes: file-browse + 8-row preview table + column-mapping controls. Nodes scope: ID column selector (node number or label matching). Edges scope: Source and Target column selectors with auto-detection of common names (source, src, target, tgt, dest). Import button is disabled until a valid file is loaded.
    • Graph::vertexAttributesImport() and Graph::edgeAttributesImport(): smart column routing — editable native columns (Label, Size, Color for nodes; Weight, Label, Color for edges) are routed to their proper setters; read-only native columns (Visible, Shape, Relation) are silently skipped; all other columns become custom attributes.
    • Each tab in the Data Table dock gains Import CSV and Import JSON buttons; the table auto-refreshes and the status bar reports the number of matched rows after import.
    • Enables a full lossless export→import roundtrip: re-importing an exported file produces no duplicate columns and no data loss.
  • Spreadsheet-based bulk attribute editing workflow (#232):

    • Emergent capability unlocked by combining #226 (export) and #227 (import): export the data table to CSV or JSON, edit it freely in any spreadsheet tool (Excel, LibreOffice, Google Sheets), and re-import to update attributes in bulk. Each node/edge can carry different values — unlike in-app bulk operations (#228) which assign one value to many.
    • Native columns updated via their proper setters on re-import; no duplicate custom-attribute columns created.

Improvements

  • Force-directed layouts improved for large graphs:
    • Fruchterman-Reingold: pre-cached adjacency (O(1) edge lookup in inner loop), initial random placement, early convergence detection.
    • Kamada-Kawai: canvas clamping replaces random teleport on out-of-bounds particles.

Bug Fixes

  • Fixed Kamada-Kawai crash when node filters are active.
  • Fixed crash on graph reset: guard edge creation in setEdgeVisibility when the edge has already been removed (#231).
  • Fixed visibility history stack not cleared on graph clear / initApp.
  • Fixed custom node attribute key/id mismatch in GraphML export (#208).
  • Fixed Pajek parser: use default node shape as fallback when no Pajek shape keyword is present (#179).
  • Fixed DialogClusteringHierarchical signal/slot mismatch (#194).
  • Fixed Node Properties dialog UX issues for custom attributes (#130).
  • Fixed graphTriadCensus() appending stale zeros on repeated runs.

Refactoring

  • New Graph::vertexOutNeighborsSet(): returns enabled 1-hop out-neighbors in the current relation; parametric for directed/undirected use.
  • Renamed vertexNeighborhoodList/SetvertexReciprocalNeighborsList/Set to reflect that only reciprocal edges are considered.

Testing / CI

  • New socnetv-cli clustering kernel v6 with golden baselines and benchmark coverage.
  • Aligned clustering benchmarks with CLI behavior; documented --type semantics.

Build / Packaging

  • RPM spec fixes: conditional Qt5Compat BuildRequires per distro family, correct qt6-qttools-devel for Fedora, dropped redundant license/doc macros.

[3.4] – March 2026

New Features

  • Two-mode sociomatrix import: correctly handles bipartite networks in parser (#15).
  • Faithful Eades (1984) Spring Embedder implementation (#207).
  • New layoutRandomInMemory() replaces layoutRandom() in force-directed pipelines (#206).

Bug Fixes

  • Progress dialog / Cancel (#52): comprehensive fix across all computation paths:
    • Wired Cancel into centrality, prestige, reachability, walks, matrix, report, layout, clique, and subgraph computations.
    • Fixed cancel-then-retry regression (reset canceled flag + invalidate distance cache).
    • Fixed stacked progress dialogs in multi-phase computations (KK layout, matrix functions).
    • All write* report functions converted to bool return; MW slots guarded on cancel.
    • All random network generators (Erdos-Renyi, Small-World, Scale-Free, Regular, Lattice, Ring-Lattice) fixed: bool return, cancel guards, progress max corrections.
  • Layouts:
    • Fixed division-by-zero, NaN/Inf and logic errors in Kamada-Kawai layout (#198).
    • Fixed FR simmering temperature derivation from canvas width (#199).
    • Batched setNodePos emissions in all force-directed layouts (#205, #206).
  • Centrality:
    • Fixed eigenvector centrality isolate reset and N==0 handling (#202).
    • Fixed Information Centrality isolate handling and degenerate cases (#201).
    • Fixed wrong vertex checked for isIsolated in createMatrixAdjacencyInverse() (#190).
    • Fixed clustering coefficient computation for directed networks (#58).
    • Fixed wrong weighted flag when switching relations (#82).
  • Parsers / IO:
    • Fixed Pajek *Matrix header parsing for relation labels (#188).
    • Fixed Pajek multirelational export as *Matrix blocks (#184).
    • Fixed quoted relation name normalization in Pajek headers (#185).
    • Fixed inline GML node/edge block parsing (#186).
    • Fixed arc doubling when loading undirected DOT graphs (#187).
    • Fixed platform-dependent weighted=true from uninitialized initEdgeWeight in DOT parser (#189).
    • Fixed Graph::setDirected() logic bugs.
  • Fixed lattice network edge deduplication and progress tracking.
  • Fixed version comparison in update-check (component-wise instead of integer).
  • Fixed #133 (see commit).

Refactoring (WS4 – IO/Parser)

  • Completed WS4: IO/Parser refactor into focused modules:
    • Extracted edgelist, adjacency, UCINET DL, DOT, GML, Pajek, GraphML parsers into separate files.
    • Introduced IGraphParseSink explicit mutation surface and GraphParseSinkGraph bridge.
    • Switched GUI and headless load paths to sink-backed parser mutations.
    • Removed legacy Parser→Graph signal wiring.
    • Parser::load and adjacency parser use ParseConfig.

Toolchain / Testing

  • New socnetv-cli schema v5 io_roundtrip kernel for IO/parser regression protection.
  • Added IO roundtrip timing regression to benchmarks.
  • Expanded golden comparison suite with many new IO roundtrip cases and small deterministic test networks.
  • Added run_io_roundtrip_shipped_datasets.sh and run_golden_io_roundtrip.sh scripts.
  • Added UCINET FT5 io_roundtrip golden baselines.
  • Fixed run_golden_compares.sh argument parsing.
  • Fixed headless parser lifetime and signal race condition.

i18n

  • Added update_translations.sh script; updated translation files.

Build / Packaging

  • Debian packaging: switched to CMake build, series-aware Qt6 deps, added OpenGL/Vulkan/XKB build deps.

  • CMake: .qm files now generated via qt_add_lrelease.

  • Fixed Windows linker /VERSION for PE header.

  • Help menu now links to socnetv.org/manual/.

  • Many bugfixes, see: GitHub Issues.

[3.3] – February 2026

  • Major internal refactor: Graph is now a façade/coordinator; functionality has been split into focused src/graph/* modules.
  • Extracted and stabilized DistanceEngine; added deterministic golden regression outputs and performance benchmark guardrails.
  • New headless regression harness socnetv-cli (modular kernels + schema-versioned JSON):
    • distance (v1), reachability (v2), walks_matrix (v3), prominence (v4)
    • strict JSON dump/compare mode with committed baselines.
  • New feature: filter vertices by centrality and prestige indices.
  • Fixed Pajek parsing edge cases (mixed files with overlapping *Arcs/*Edges blocks).
  • Fixed UCINET/DL import edge cases (line wrapping, diagonal handling).
  • Fixed walks computation (walksBetween() / walks matrix parameter issues).
  • Improved tie/link counting semantics on load (canonical ties + derived SNA links; density exposed in regression JSON).
  • UI polish: improved disabled widget styling and custom SVG checkbox/radio styling.
  • Cross-platform build & packaging fixes (Qt6/CMake, Debian packaging updates, openSUSE spec fixes, macOS arm64 linker fix).
  • Many bugfixes, see: GitHub Issues.

[3.2] – April 2025

  • Support custom attributes (metadata) in nodes (via the Node Properties dialog).
  • Support for node labels in adjacency matrix formatted files.
  • New CMake-based build system.
  • Updated look and behavior of Filter Edges by Weight functionality.
  • Many bugfixes, see: GitHub Issues.

[3.1] – June 2023

  • Version 3.1 released, our first Qt6-only version.
  • Improved large file loading and responsiveness with large networks (>20,000 edges).
  • Reduced memory footprint.
  • Fixed edge filtering (see issue #140).
  • Enhanced "Find Node by Index Score" dialog for more meaningful comparisons.
  • Fixed numerous bugs.
  • Improved usability and help messages.

[3.0] – July 2021

  • Version 3.0 released for Windows, macOS, and Linux, with improved graph calculation speed and new command-line parameters.
  • First version to support hardware-accelerated (OpenGL) rendering of networks.
  • Improved Web Crawler:
    • Tests for OpenSSL support in the OS and provides user hints if OpenSSL is missing.
    • Fixed delay between requests.
  • Fixed a serious bug in weighted network centrality computations (see issue #123).
  • Note: To run SocNetV 3.0 AppImage in Fedora 34 (which uses Wayland by default), use: env GDK_BACKEND=x11 ./SocNetV-3.0-dev-x86_64.AppImage
  • OBS repositories are working again. Fedora/openSUSE packages can be downloaded from: OBS Repositories

[2.9] – June 2021

  • Version 2.9 released, bugfixes
  • Version 3.0 development. To run 3.0-dev in Fedora, use: env GDK_BACKEND=x11 ./SocNetV-3.0-dev-x86_64.AppImage

[2.8] – Jan 2021

  • Version 2.8, with some bugfixes

[2.7] – Dec 2020

  • Version 2.6 and 2.7 release with bugfixes and new features.

[2.5] – Feb 2019

  • Version 2.5 released with new features and bugfixes.
  • Prominence scores distribution in reports and in-app mini chart.
  • Support for custom node icons (PNG, JPEG, SVG, etc).
  • Edge dichotomization algorithm.
  • High quality theme, inspired by Material Design, for uniform look and feel of SocNetV across all OSes.
  • Support for (double) edge weights in all formats.
  • Improved export to PDF and Image (with lots of new formats).
  • Improved web crawler.
  • Lattice network generator.
  • Improved memory consumption and faster measure computations.
  • Search and select multiple nodes by their numbers, labels, or prominence scores.
  • Many bug fixes.

[2.4] – Feb 2018

  • Version 2.4 released with many new features.
  • New Force-Directed Placement layout: Kamada-Kawai.
  • New layout type by prominence score: Node colors.
  • Less clutter in visualization due to reciprocated edges. These are now being drawn in a single line.
  • Improved memory consumption during user interaction with large networks
  • Improved web crawler with pattern include and exclude options
  • Improved Statistics Panel.
  • Performance options in Settings dialog
  • Improved UCINET format support (fullmatrix two-mode and edgelist).
  • New "Check for updates" procedure.
  • Much improved stability. See Changelog for bugs closed.

[2.3] – Jul 2017

  • Version 2.3 released with bugfixes and new features:
  • Dyad and Actor/Ego reciprocity
  • Zero-weighted edge support and zero-weighted edge color selection functionality in Settings
  • Bug Closed:
  • #28 Edges with values in [-1,0) are not visible
  • #29 Settings: Negative edge colour preferences break positive edge colours

[2.2] – Jan 2017

  • Version 2.2 released with major new features.
  • Hierarchical Clustering Analysis (HCA)
  • Pearson correlation coefficients
  • Actor Similarities
  • Tie profile dissimilarities
  • Maximal clique census
  • New network symmetrization methods: Strong Ties, Cocitation
  • Multi-relational data read and write in GraphML
  • GML format support
  • Support for EdgeLists with labels
  • Support for Pajek multirelational directed networks
  • Adjacency matrix plotting
  • Better reports (in HTML with JS)
  • Improved performance and GUI

[2.1] – Sep 2016

  • Version 2.1 released with a few new features but lots of bug fixes. This version brings a new algorithm for d-regular random network generation, and also a nice new dialog to control it. See ChangeLog for a complete log of new features and bugfixes.
  • Version 2.0 released with major code overhaul, new GUI layout and lots of bugfixes and improvements. The new version brings stability, great performance boost, and nice new features such as separate modes for graphs and digraphs, permanent settings/preferences functionality, edge labeling, recent files, keyboard shortcuts, etc. Also there are improvements in Force-Directed layouts, i.e. Fructherman-Reingold. See ChangeLog for a complete overview of the new features.
  • The SocNetV Manual is now build with Doxygen and it is available at http://socnetv.sf.net/documentation

[1.9] – June 2015

  • Version 1.9 released with lots of bugfixes and a faster matrix inverse routine using LU decomposition. Also Information Centrality is greatly improved in terms of computation speed. PageRank Prestige algorithm corrected to compute PR using the correct formula. The initial PR score of each node is now 1/N. Bugs closed: #1463069 wrong average distance when there are isolates #1365037 certain sparse matrices crash socnetv on invertMatrix method #1365582 centralityInformation() is slow when network N>100 #1463095 edge filter works but the user cannot undo #1464422 wrong pagerank results #1464430 socnetv refuses to read pajek files not starting with *Network #1465774 edges do not always follow relations #1463082 edge color change is not taking place #1464418 socnetv crashes on pagerank computation on isolated nodes

  • Version 1.8 released with the following new features: New clique census routine to compute maximal cliques with up to 4 vertices. New Scale-free random generation methods. Improved Erdos-Renyi generation to include G(n,M) model. Fixed bug in Clustering Coefficient - SocNetV now computes CluCof correctly in all cases. New improved dialogs for easy random network generation (Scale-free, Erdos-Renyi, and Small-World) Fixed bug in Node Properties dialog. It is now populated with current node settings.

[1.7] – May 2015

  • Version 1.7 released. New node group select/edit functionality and file previewer supporting different codecs
  • Version 1.6 released. New and improved web crawler functionality. See Changelog for more.

[1.5] – Oct 2014

  • Version 1.5 released. First version with dijkstra algorithm for the SSSP in weighted nets. See Changelog for more.

[1.4] – Sep 2014

  • Version 1.4 released. Brought new layout type (nodal size by prominence index), edgelist1 UCINET format import method and many bugfixes.

[1.3] – Aug 2014

  • Version 1.3 released.
  • First time SocNetV works with multigraphs

[1.2] – Aug 2014

  • Version 1.2 released. It features a major GUI overhaul and brings in a new "prominence indices" conceptualization based on Wasserman & Faust. In general, Centrality indices focus on outLinks (choices given) while Prestige indices consider inLinks (choices received). Added 3 Prestige indices (Degree, Proximity and PageRank), new reachability measures (Walks, Connectedness, and Reachability Matrix) and fixed a slew of bugs in indices calculation. All algorithms are now tested to report 100% correct results.
  • Version 1.1 released with major bug fixes. See ChangeLog.
  • First time distribution of a disk image for installation in Mac OS X

[1.0] – Feb 2014

  • Version 1.0 released, starting a new 1.x series based on Qt5. The 0.x series is no longer maintained. Please upgrade :)
  • PageRank calculation and layout
  • SRS Documentation by Vagelis Motesnitsalis

July 2013

  • Moved project code to git/BB
  • Started development for Qt5

Oct 2010

  • Version 0.90 released
  • New Power & Information Centralities

Jan 2010

  • Version 0.80
  • New List import feature
  • New Triad Census feature
  • Various Bug Fixes

June 2009

  • Version 0.70
  • First web crawler implementation

May 2009

  • Version 0.6 (release)
  • GraphML becomes native SocNetV load format

Feb 2009

  • Version 0.51 (bugfix release)
  • Version 0.50 (released)
  • Small world creation
  • Clustering coefficient
  • Exporting to PDF
  • Printing works OK.

Jan 2009

  • Version 0.49 (released)
  • Ubuntu repository created.

Sep 2008

  • New logo
  • New openSUSE package repo.
  • Version 0.48 released
  • Version 0.47 released
  • Version 0.46 released. Lots of bugfixes. New features:
    • Node sizes may reflect degree.

Aug 2008

  • New Debian Package
  • Version 0.45 released. New features:
    • GraphML initial support.
    • New man page and updated online documentation.
    • HtmlViewer renders online help with the help of QtWebKit (openSUSE: libQtWebKit-devel)
    • New widget for network rotation.
    • New widget for zooming replaces the old one.
    • Nodes may have 4 different shapes: circles, diamonds, triangles, boxes and ellipses are supported.
    • There was a bug in Qt 4.3 QGraphicsView causing redraw delays. Is fixed in Qt 4.4 :)
    • Cosmetic changes, i.e. new icons, new layout for the left dock.
    • Code clean-up in MainWindows Class and Matrix.
    • Deleted obsolete members and functions such as nodeExists(), mousePosGW(), Dijkstra, etc.
    • Bug-fixes on loading Pajek networks and layout algorithm.

May 2008

  • Version 0.44 released one year after v.0.43. New features: Ported to Qt4: Code rewritten almost from scratch. Splitted MainWindow/GUI from algorithms via a new Graph Class. Improved GUI with docks. Network zooming via mouse wheel. Spring Embedder: Dynamic network reallocation Thread support. Much faster calculation of distances and centralities (BFS/dijkstra). Betweenness centrality now is much more efficiently calculated. Changed license to GPL3 Layout in circles and levels by centrality. Better graphics and antialiasing (disabled - enable by pressing F8). New centrality index: Eccentricity.

Sep 2006

  • version 0.43 released with new layout features.

June 2006

  • version 0.42 released with updated help files.

May 2006

March 2006

  • version 0.41 released.

February 2006

  • version 0.40 released. Efforts to be a pretty trustworthy release.
  • sourceforge project downloads are more than enough daily, but there is no feedback yet for versions 0.38 and 0.39.
  • version 0.39 released. Somewhat rushed release.
  • constant changes in the homepage.
  • updated links in www.insna.org

January 2006

  • version 0.38 released after one year of silence.
  • The project moved to sourceforge.net
  • The homepage is https://socnetv.org