Quick Start¶
Note on Wrappers: Please report any bugs you find while using the language wrappers. I am moving quickly and relying on AI to speed up the development of these wrappers, but I am actively and carefully maintaining the core C backend.
Python¶
from dress import fit
result = fit(
n_vertices=4,
sources=[0, 1, 2, 0],
targets=[1, 2, 3, 3],
)
print(f"Iterations: {result.iterations}")
print(f"Edge DRESS values: {result.edge_dress}")
print(f"Node DRESS values: {result.vertex_dress}")
Δ^k-DRESS (Python)¶
from dress import delta_fit
result = delta_fit(
n_vertices=4,
sources=[0, 1, 2, 0],
targets=[1, 2, 3, 3],
k=1, # remove 1 vertex at a time
epsilon=1e-6,
)
print(result.histogram) # [(value, count), ...]
print(f"Total edge-values: {sum(count for _, count in result.histogram)}")
print(f"Subgraphs: {result.num_subgraphs}")
NetworkX (Python)¶
import networkx as nx
from dress.networkx import fit, delta_fit
G = nx.karate_club_graph()
# Δ⁰: DRESS on the full graph
result = fit(G, set_attributes=True)
print(G.edges[0, 1]["dress"]) # per-edge similarity
print(G.nodes[0]["vertex_dress"]) # per-vertex norm
# Δ¹: histogram fingerprint
delta = delta_fit(G, k=1)
print(delta.histogram) # [(value, count), ...]
GPU and MPI variants, same API, different import:
from dress.cuda.networkx import fit # GPU
from dress.mpi.networkx import delta_fit # MPI CPU
from dress.mpi.cuda.networkx import delta_fit # MPI+CUDA
Rust¶
use dress_graph::{DRESS, Variant};
let mut g = DRESS::new(4, vec![0, 1, 2, 0], vec![1, 2, 3, 3],
None, None, Variant::Undirected, false).unwrap();
let (iters, delta) = g.fit(100, 1e-6);
let r = g.result();
println!("iterations: {}", iters);
for (i, d) in r.edge_dress.iter().enumerate() {
println!(" edge {}: dress = {:.6}", i, d);
}
Δ^k-DRESS (Rust)¶
use dress_graph::{fit, delta_fit, Variant};
let r = delta_fit(
4,
vec![0, 1, 2, 0],
vec![1, 2, 3, 3],
None, // edge weights
None, // vertex weights
Variant::Undirected,
false, // precompute
1, // k = 1
100, // max iterations
1e-6,
0, 0, // n_samples, seed
false, // keep multisets
true, // compute histogram
).unwrap();
println!("histogram entries: {:?}", r.histogram);
let total: i64 = r.histogram.iter().map(|entry| entry.count).sum();
println!("total edge-values: {}", total);
C¶
Install via Homebrew, vcpkg, or build from source:
# Homebrew
brew tap velicast/dress-graph && brew install dress-graph
# vcpkg (overlay port)
vcpkg install dress-graph --overlay-ports=/path/to/dress-graph/vcpkg
# From source
mkdir build && cd build && cmake .. && make
#include <stdio.h>
#include <stdlib.h>
#include "dress/dress.h"
int main(void) {
int N = 4, E = 4;
/* Allocate with malloc. dress_init_graph takes ownership. */
int *U = malloc(E * sizeof *U);
int *V = malloc(E * sizeof *V);
U[0] = 0; V[0] = 1;
U[1] = 1; V[1] = 2;
U[2] = 2; V[2] = 3;
U[3] = 0; V[3] = 3;
p_dress_graph_t g = dress_init_graph(N, E, U, V, NULL, NULL,
DRESS_VARIANT_UNDIRECTED, 1);
int iterations;
double delta;
dress_fit(g, 100, 1e-6, &iterations, &delta);
printf("iterations: %d, delta: %e\n", iterations, delta);
for (int e = 0; e < g->E; e++)
printf(" edge (%d,%d): dress = %.6f\n",
g->U[e], g->V[e], g->edge_dress[e]);
dress_free_graph(g);
return 0;
}
Δ^k-DRESS (C)¶
#include "dress/dress.h"
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int N = 4, E = 4;
int *U = malloc(E * sizeof *U);
int *V = malloc(E * sizeof *V);
U[0]=0; V[0]=1; U[1]=1; V[1]=2;
U[2]=2; V[2]=3; U[3]=0; V[3]=3;
p_dress_graph_t g = dress_init_graph(N, E, U, V, NULL, NULL,
DRESS_VARIANT_UNDIRECTED, 0);
int hist_size;
int64_t num_subgraphs;
dress_hist_pair_t *hist = dress_delta_fit(g, 1, 100, 1e-6,
0, 0, // n_samples, seed
&hist_size, 0, NULL, &num_subgraphs);
int64_t total = 0;
for (int i = 0; i < hist_size; i++) total += hist[i].count;
printf("entries: %d, total: %ld\n", hist_size, total);
free(hist);
dress_free_graph(g);
return 0;
}
C++¶
#include <cstdio>
#include "dress/dress.hpp"
using namespace dress;
int main() {
DRESS g(4,
{0, 1, 2, 0}, // sources
{1, 2, 3, 3}); // targets
auto [iters, delta] = g.fit(100, 1e-6);
printf("iterations: %d, delta: %e\n", iters, delta);
for (int e = 0; e < g.numEdges(); e++)
printf(" edge (%d,%d): dress = %.6f\n",
g.edgeSource(e), g.edgeTarget(e), g.edgeDress(e));
}
Δ^k-DRESS (C++)¶
#include <cstdio>
#include "dress/dress.hpp"
using namespace dress;
int main() {
DRESS g(4, {0,1,2,0}, {1,2,3,3});
auto r = g.deltaFit(1, 100, 1e-6);
int64_t total = 0;
for (const auto& [val, cnt] : r.histogram) total += cnt;
printf("entries: %zu, total: %ld\n", r.histogram.size(), total);
}
Go¶
import "github.com/velicast/dress-graph/go"
result, err := dress.Fit(4,
[]int32{0, 1, 2, 0},
[]int32{1, 2, 3, 3},
nil, // no weights
nil, // no vertex weights
dress.Undirected, 100, 1e-6, true)
fmt.Printf("iterations: %d\n", result.Iterations)
Δ^k-DRESS (Go)¶
r, err := dress.DeltaFit(4,
[]int32{0, 1, 2, 0},
[]int32{1, 2, 3, 3},
nil, // edge weights
nil, // vertex weights
1, // k
dress.Undirected,
100, 1e-6,
0, 0, // n_samples, seed
false, false, true) // precompute, keepMultisets, computeHistogram
total := int64(0)
for _, entry := range r.Histogram { total += entry.Count }
fmt.Printf("entries: %d, total: %d\n", len(r.Histogram), total)
JavaScript (WASM)¶
import { fit, Variant } from './dress.js';
const result = await fit({
numVertices: 4,
sources: [0, 1, 2, 0],
targets: [1, 2, 3, 3],
variant: Variant.UNDIRECTED,
});
console.log(`iterations: ${result.iterations}`);
console.log('edge dress:', result.edgeDress);
Δ^k-DRESS (WASM)¶
import { deltaFit } from './dress.js';
const r = await deltaFit({
numVertices: 4,
sources: [0, 1, 2, 0],
targets: [1, 2, 3, 3],
k: 1,
epsilon: 1e-6,
});
let total = 0;
for (const entry of r.histogram) total += entry.count;
console.log(r.histogram);
console.log(`total: ${total}`);
R¶
library(dress.graph)
res <- fit(
n_vertices = 4L,
sources = c(0L, 1L, 2L, 0L),
targets = c(1L, 2L, 3L, 3L)
)
cat("iterations:", res$iterations, "\n")
cat("edge dress:", res$edge_dress, "\n")
cat("node dress:", res$vertex_dress, "\n")
Δ^k-DRESS (R)¶
r <- delta_fit(4L, c(0L,1L,2L,0L), c(1L,2L,3L,3L),
k = 1L, epsilon = 1e-6)
print(r$histogram)
cat("total:", sum(r$histogram$count), "\n")
Julia¶
using DRESS
result = fit(4, Int32[0, 1, 2, 0], Int32[1, 2, 3, 3];
variant=UNDIRECTED)
println("iterations: ", result.iterations)
println("edge dress: ", result.edge_dress)
Δ^k-DRESS (Julia)¶
r = delta_fit(4, Int32[0,1,2,0], Int32[1,2,3,3];
k=1, epsilon=1e-6)
println("histogram: ", r.histogram)
println("total: ", sum(entry.count for entry in r.histogram))
MATLAB / Octave¶
result = fit(4, int32([0 1 2 0]), int32([1 2 3 3]));
fprintf('iterations: %d\n', result.iterations);
disp(result.edge_dress);
Δ^k-DRESS (MATLAB / Octave)¶
r = delta_fit(4, int32([0 1 2 0]), int32([1 2 3 3]), ...
'K', 1, 'Epsilon', 1e-6);
disp(r.histogram.value);
disp(r.histogram.count);
OO and backend-switched variants use the same namespace pattern in both MATLAB and Octave:
g = DRESS(4, int32([0 1 2 0]), int32([1 2 3 3])); % CPU
gc = cuda.DRESS(4, int32([0 1 2 0]), int32([1 2 3 3])); % CUDA
gm = mpi.DRESS(4, int32([0 1 2 0]), int32([1 2 3 3])); % MPI
gg = mpi.cuda.DRESS(4, int32([0 1 2 0]), int32([1 2 3 3])); % MPI+CUDA
r = gm.delta_fit('K', 1, 'KeepMultisets', true);
disp(r.histogram.value);
disp(r.histogram.count);