Skip to content

Commit

Permalink
Change threshold to compression_level for CompressedGraph; rename mat…
Browse files Browse the repository at this point in the history
…rix_string_representation to matrix_string
  • Loading branch information
ted-tanner committed Nov 29, 2022
1 parent 624afa9 commit 36178e5
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 183 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ members = [

[workspace.package]
authors = ["Tanner Davies"]
version = "1.1.0"
version = "1.2.0"
edition = "2021"
description = "A graph library for graph compression and fast processing of graph approximations"
license = "MIT"
4 changes: 2 additions & 2 deletions graphrox-c/gphrx.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const GphrxCsrSquareMatrix gphrx_find_avg_pool_matrix(const GphrxGraph graph,
GphrxGraph gphrx_approximate(const GphrxGraph graph,
uint64_t block_dimension,
double threshold);
const GphrxCompressedGraph gphrx_compress(const GphrxGraph graph, double threshold);
const GphrxCompressedGraph gphrx_compress(const GphrxGraph graph, uint8_t compression_level);
const GphrxGraphEdge *gphrx_get_edge_list(const GphrxGraph graph, size_t *length);

void gphrx_add_vertex(GphrxGraph graph,
Expand All @@ -85,7 +85,7 @@ void free_gphrx_compressed_graph(const GphrxCompressedGraph graph);

GphrxCompressedGraph gphrx_compressed_graph_duplicate(const GphrxCompressedGraph graph);

double gphrx_compressed_graph_threshold(const GphrxCompressedGraph graph);
uint8_t gphrx_compressed_graph_compression_level(const GphrxCompressedGraph graph);
int8_t gphrx_compressed_graph_is_undirected(const GphrxCompressedGraph graph);
uint64_t gphrx_compressed_graph_vertex_count(const GphrxCompressedGraph graph);
uint64_t gphrx_compressed_graph_edge_count(const GphrxCompressedGraph graph);
Expand Down
70 changes: 41 additions & 29 deletions graphrox-c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ pub unsafe extern "C" fn gphrx_matrix_string(graph: GphrxGraph) -> *mut ffi::c_c
.as_ref()
.unwrap_unchecked();

ffi::CString::from_vec_unchecked((*graph).matrix_representation_string().as_bytes().to_vec())
.into_raw()
ffi::CString::from_vec_unchecked((*graph).matrix_string().as_bytes().to_vec()).into_raw()
}

#[no_mangle]
Expand Down Expand Up @@ -247,12 +246,15 @@ pub unsafe extern "C" fn gphrx_approximate(
}

#[no_mangle]
pub unsafe extern "C" fn gphrx_compress(graph: GphrxGraph, threshold: f64) -> GphrxCompressedGraph {
pub unsafe extern "C" fn gphrx_compress(
graph: GphrxGraph,
compression_level: u8,
) -> GphrxCompressedGraph {
let graph = (graph.graph_ptr as *const Graph)
.as_ref()
.unwrap_unchecked();

let compressed_graph = graph.compress(threshold);
let compressed_graph = graph.compress(compression_level);

GphrxCompressedGraph {
graph_ptr: Box::into_raw(Box::new(compressed_graph)) as *mut _,
Expand Down Expand Up @@ -403,12 +405,14 @@ pub unsafe extern "C" fn gphrx_compressed_graph_duplicate(
}

#[no_mangle]
pub unsafe extern "C" fn gphrx_compressed_graph_threshold(graph: GphrxCompressedGraph) -> f64 {
pub unsafe extern "C" fn gphrx_compressed_graph_compression_level(
graph: GphrxCompressedGraph,
) -> u8 {
let graph = (graph.graph_ptr as *const CompressedGraph)
.as_ref()
.unwrap_unchecked();

graph.threshold()
graph.compression_level()
}

#[no_mangle]
Expand Down Expand Up @@ -482,8 +486,7 @@ pub unsafe extern "C" fn gphrx_compressed_graph_matrix_string(
.as_ref()
.unwrap_unchecked();

ffi::CString::from_vec_unchecked((*graph).matrix_representation_string().as_bytes().to_vec())
.into_raw()
ffi::CString::from_vec_unchecked((*graph).matrix_string().as_bytes().to_vec()).into_raw()
}

#[no_mangle]
Expand Down Expand Up @@ -1095,13 +1098,16 @@ mod tests {
gphrx_add_edge(graph, 22, 18);
gphrx_add_edge(graph, 15, 18);

let compressed_graph = gphrx_compress(graph, 0.2);
let compressed_graph = gphrx_compress(graph, 9);

assert_eq!(
gphrx_compressed_graph_is_undirected(compressed_graph),
gphrx_is_undirected(graph)
);
assert_eq!(gphrx_compressed_graph_threshold(compressed_graph), 0.2);
assert_eq!(
gphrx_compressed_graph_compression_level(compressed_graph),
9
);
assert_eq!(
gphrx_compressed_graph_vertex_count(compressed_graph),
gphrx_vertex_count(graph)
Expand Down Expand Up @@ -1483,7 +1489,7 @@ mod tests {
gphrx_add_edge(graph, 22, 18);
gphrx_add_edge(graph, 15, 18);

let compressed_graph = gphrx_compress(graph, 0.2);
let compressed_graph = gphrx_compress(graph, 4);

free_gphrx_graph(graph);

Expand Down Expand Up @@ -1514,14 +1520,17 @@ mod tests {
gphrx_add_edge(graph, 22, 18);
gphrx_add_edge(graph, 15, 18);

let compressed_graph = gphrx_compress(graph, 0.2);
let compressed_graph = gphrx_compress(graph, 6);
let compressed_graph_dup = gphrx_compressed_graph_duplicate(compressed_graph);

assert_eq!(
gphrx_compressed_graph_is_undirected(compressed_graph_dup),
gphrx_is_undirected(graph)
);
assert_eq!(gphrx_compressed_graph_threshold(compressed_graph_dup), 0.2);
assert_eq!(
gphrx_compressed_graph_compression_level(compressed_graph_dup),
6
);
assert_eq!(
gphrx_compressed_graph_vertex_count(compressed_graph_dup),
gphrx_vertex_count(graph)
Expand All @@ -1548,15 +1557,18 @@ mod tests {
}

#[test]
fn test_gphrx_compressed_graph_threshold() {
fn test_gphrx_compressed_graph_compression_level() {
let graph = gphrx_new_directed();

unsafe {
gphrx_add_edge(graph, 10, 1);

let compressed_graph = gphrx_compress(graph, 0.42);
let compressed_graph = gphrx_compress(graph, 42);

assert_eq!(gphrx_compressed_graph_threshold(compressed_graph), 0.42);
assert_eq!(
gphrx_compressed_graph_compression_level(compressed_graph),
42
);

free_gphrx_graph(graph);
free_gphrx_compressed_graph(compressed_graph);
Expand All @@ -1568,7 +1580,7 @@ mod tests {
let graph = gphrx_new_undirected();

unsafe {
let compressed_graph = gphrx_compress(graph, 0.1);
let compressed_graph = gphrx_compress(graph, 2);
assert_eq!(
gphrx_compressed_graph_is_undirected(compressed_graph),
C_TRUE
Expand All @@ -1578,7 +1590,7 @@ mod tests {
let graph = gphrx_new_directed();

unsafe {
let compressed_graph = gphrx_compress(graph, 0.1);
let compressed_graph = gphrx_compress(graph, 10);
assert_eq!(
gphrx_compressed_graph_is_undirected(compressed_graph),
C_FALSE
Expand All @@ -1593,7 +1605,7 @@ mod tests {
unsafe {
gphrx_add_edge(graph, 10, 1);

let compressed_graph = gphrx_compress(graph, 0.0);
let compressed_graph = gphrx_compress(graph, 0);

assert_eq!(gphrx_compressed_graph_vertex_count(compressed_graph), 11);

Expand All @@ -1609,7 +1621,7 @@ mod tests {
unsafe {
gphrx_add_edge(graph, 10, 1);

let compressed_graph = gphrx_compress(graph, 0.0);
let compressed_graph = gphrx_compress(graph, 0);

assert_eq!(gphrx_compressed_graph_edge_count(compressed_graph), 2);

Expand All @@ -1622,7 +1634,7 @@ mod tests {
unsafe {
gphrx_add_edge(graph, 10, 1);

let compressed_graph = gphrx_compress(graph, 0.0);
let compressed_graph = gphrx_compress(graph, 0);

assert_eq!(gphrx_compressed_graph_edge_count(compressed_graph), 1);

Expand Down Expand Up @@ -1653,7 +1665,7 @@ mod tests {
gphrx_add_edge(graph, 22, 18);
gphrx_add_edge(graph, 15, 18);

let compressed_graph = gphrx_compress(graph, 0.2);
let compressed_graph = gphrx_compress(graph, 7);

for i in 8..16 {
for j in 8..16 {
Expand Down Expand Up @@ -1706,7 +1718,7 @@ mod tests {
}
}

let compressed_graph = gphrx_compress(graph, 0.2);
let compressed_graph = gphrx_compress(graph, 13);

assert_eq!(gphrx_get_compressed_matrix_entry(compressed_graph, 0, 0), 0);
assert_eq!(
Expand Down Expand Up @@ -1746,7 +1758,7 @@ mod tests {
}
}

let compressed_graph = gphrx_compress(graph, 0.2);
let compressed_graph = gphrx_compress(graph, 4);
let compressed_graph_string =
ffi::CString::from_raw(gphrx_compressed_graph_matrix_string(compressed_graph));
let compressed_graph_string = compressed_graph_string.as_c_str().to_str().unwrap();
Expand All @@ -1763,7 +1775,7 @@ mod tests {

#[test]
fn test_gphrx_compressed_graph_to_from_bytes() {
const SIZE_OF_COMPRESSED_GRAPH_BYTES_HEADER: usize = 49;
const SIZE_OF_COMPRESSED_GRAPH_BYTES_HEADER: usize = 42;
let graph = gphrx_new_directed();

unsafe {
Expand All @@ -1781,7 +1793,7 @@ mod tests {
}
}

let compressed_graph = gphrx_compress(graph, 0.25);
let compressed_graph = gphrx_compress(graph, 25);

let mut size = 0;
let bytes = gphrx_compressed_graph_to_bytes(compressed_graph, &mut size as *mut _);
Expand All @@ -1802,8 +1814,8 @@ mod tests {
gphrx_is_undirected(graph)
);
assert_eq!(
gphrx_compressed_graph_threshold(compressed_graph_from_bytes),
0.25
gphrx_compressed_graph_compression_level(compressed_graph_from_bytes),
25
);
assert_eq!(
gphrx_compressed_graph_vertex_count(compressed_graph_from_bytes),
Expand Down Expand Up @@ -1853,7 +1865,7 @@ mod tests {
}
}

let compressed_graph = gphrx_compress(graph, 0.2);
let compressed_graph = gphrx_compress(graph, 23);
let decompressed_graph = gphrx_decompress(compressed_graph);

assert_eq!(
Expand Down
38 changes: 21 additions & 17 deletions graphrox-py/graphrox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class _GphrxError(enum.Enum):
_lib.gphrx_approximate.argtypes = (_GphrxGraph_c, ctypes.c_uint64, ctypes.c_double)
_lib.gphrx_approximate.restype = _GphrxGraph_c

_lib.gphrx_compress.argtypes = (_GphrxGraph_c, ctypes.c_double)
_lib.gphrx_compress.argtypes = (_GphrxGraph_c, ctypes.c_uint8)
_lib.gphrx_compress.restype = _GphrxCompressedGraph_c

_lib.gphrx_get_edge_list.argtypes = (_GphrxGraph_c, ctypes.POINTER(ctypes.c_size_t))
Expand Down Expand Up @@ -177,8 +177,8 @@ class _GphrxError(enum.Enum):
_lib.gphrx_compressed_graph_duplicate.argtypes = [_GphrxCompressedGraph_c]
_lib.gphrx_compressed_graph_duplicate.restype = _GphrxCompressedGraph_c

_lib.gphrx_compressed_graph_threshold.argtypes = [_GphrxCompressedGraph_c]
_lib.gphrx_compressed_graph_threshold.restype = ctypes.c_double
_lib.gphrx_compressed_graph_compression_level.argtypes = [_GphrxCompressedGraph_c]
_lib.gphrx_compressed_graph_compression_level.restype = ctypes.c_uint8

_lib.gphrx_compressed_graph_is_undirected.argtypes = [_GphrxCompressedGraph_c]
_lib.gphrx_compressed_graph_is_undirected.restype = ctypes.c_int8
Expand Down Expand Up @@ -393,7 +393,7 @@ def approximate(self, block_dimension, threshold):
c_graph = _lib.gphrx_approximate(self._graph, block_dimension, threshold)
return Graph(_c_graph=c_graph)

def compress(self, threshold):
def compress(self, compression_level):
"""Compresses a graph with a lossy algorithm.
`Graph`s can be compressed into a space-efficient form. 8x8 blocks in the graph's
Expand All @@ -402,15 +402,19 @@ def compress(self, threshold):
losslessly encoded in an unsigned 64-bit integer. If the block does not meet the
threshold, the entire block will be represented by a 0 in the resulting matrix. Because
GraphRox stores matrices as adjacency lists, 0 entries have no effect on storage size.
The average pooled adjacency matrix entries will always be in the range of [0.0, 1.0]
inclusive. The `threshold` parameter is therefore clamped between 10^(-18) and 1.0.
Any `threshold` less than 10^(-18) will be treated as 10^(-18) and any `threshold`
greater than 1.0 will be treated as 1.0.
A threshold of 0.0 is essentially a lossless compression.
`compression_level` is divided by 64 to obtain the threshold. Thus, `compression_level` is
equal to the number of entries in an 8x8 block of the adjacency matrix that must be ones in
order for the block to be losslessly encoded in the CompressedGraph. A CompressedGraph is
not necessarily approximated, though, because the `compression_level` may be one.
`compression_level` will be clamped to a number between 1 and 64 inclusive.
"""
c_compressed_graph = _lib.gphrx_compress(self._graph, threshold)
if compression_level > 64:
compression_level = 64
elif compression_level < 1:
compression_level = 1

c_compressed_graph = _lib.gphrx_compress(self._graph, compression_level)
return CompressedGraph(c_compressed_graph)

def edge_list(self):
Expand Down Expand Up @@ -628,13 +632,13 @@ def decompress(self):
c_graph = _lib.gphrx_decompress(self._graph)
return Graph(_c_graph=c_graph)

def threshold(self):
"""Returns the threshold used to create the `CompressedGraph`.
def compression_level(self):
"""Returns the compression level used to create the `CompressedGraph`.
Returns the threshold that was applied to the average pooling of the original graph's
adjacency matrix to create the CompressedGraph.
Returns the compression level that was applied to obtain the threshold for the average
pooling of the original graph's adjacency matrix to create the CompressedGraph.
"""
return float(_lib.gphrx_compressed_graph_threshold(self._graph))
return float(_lib.gphrx_compressed_graph_compression_level(self._graph))

def is_undirected(self):
"""Returns `True` if the graph is undirected. Otherwise, returns `False`."""
Expand Down
4 changes: 2 additions & 2 deletions graphrox-py/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ build-backend = "setuptools.build_meta"
[project]
name = "graphrox"
authors = [ { name = "Tanner Davies" } ]
version = "1.1.0"
version = "1.2.0"
license = { file = "LICENSE" }
requires-python = ">=3.6"
requires-python = ">=3.4"
dependencies = []
description = "A network graph library for efficiently compressing and generating approximations of graphs"
keywords = [
Expand Down
Loading

0 comments on commit 36178e5

Please sign in to comment.