triangles and clustering coefficients

main
Ziyang Hu 2 years ago
parent 3880a5ee8a
commit cd55bf3704

@ -16,7 +16,7 @@
* [x] closeness centrality
* [x] betweenness centrality
* [x] pagerank
* [ ] triangle counting
* [x] triangle counting
* [x] strongly connected components
* [x] connected components
* [ ] label propagation

@ -9,7 +9,6 @@
import {Button, DataTable, InlineLoading, TextArea} from "carbon-components-svelte";
import {DirectionStraightRight} from "carbon-icons-svelte";
import {onMount} from "svelte";
async function handleQuery() {
const query = queryText.trim();
@ -29,9 +28,8 @@
throw await response.text();
}
let res = await response.json();
statusMessage = `finished in ${res.time_taken}ms`
if (res.rows) {
statusMessage = `finished ${res.rows.length} rows in ${res.time_taken}ms`
if (!res.headers) {
res.headers = [];
if (res.rows.length) {
@ -51,6 +49,7 @@
});
queryResults = {rows, headers}
} else {
statusMessage = `finished in ${res.time_taken}ms`
queryResults = res;
}
} catch (e) {

@ -1,5 +1,6 @@
use static_files::resource_dir;
fn main() -> std::io::Result<()> {
println!("cargo:rerun-if-changed=../cozo_webui/src/App.svelte");
resource_dir("../cozo_webui/dist").build()
}

@ -15,6 +15,7 @@ use crate::algo::prim::MinimumSpanningTreePrim;
use crate::algo::shortest_path_dijkstra::ShortestPathDijkstra;
use crate::algo::strongly_connected_components::StronglyConnectedComponent;
use crate::algo::top_sort::TopSort;
use crate::algo::triangles::ClusteringCoefficients;
use crate::algo::yen::KShortestPathYen;
use crate::data::expr::Expr;
use crate::data::id::{EntityId, Validity};
@ -63,6 +64,7 @@ impl AlgoHandle {
}
pub(crate) fn arity(&self) -> Result<usize> {
Ok(match &self.name.0 as &str {
"clustering_coefficients" => 4,
"degree_centrality" => 4,
"closeness_centrality" => 2,
"betweenness_centrality" => 2,
@ -83,6 +85,7 @@ impl AlgoHandle {
pub(crate) fn get_impl(&self) -> Result<Box<dyn AlgoImpl>> {
Ok(match &self.name.0 as &str {
"clustering_coefficients" => Box::new(ClusteringCoefficients),
"degree_centrality" => Box::new(DegreeCentrality),
"closeness_centrality" => Box::new(ClosenessCentrality),
"betweenness_centrality" => Box::new(BetweennessCentrality),

@ -1,40 +1,71 @@
// use std::collections::BTreeMap;
//
// use anyhow::Result;
// use smartstring::{LazyCompact, SmartString};
//
// use crate::algo::AlgoImpl;
// use crate::data::expr::Expr;
// use crate::data::program::{MagicAlgoRuleArg, MagicSymbol};
// use crate::runtime::derived::DerivedRelStore;
// use crate::runtime::transact::SessionTx;
//
// pub(crate) struct ClusteringCoefficient;
//
// impl AlgoImpl for ClusteringCoefficient {
// fn run(
// &mut self,
// tx: &SessionTx,
// rels: &[MagicAlgoRuleArg],
// opts: &BTreeMap<SmartString<LazyCompact>, Expr>,
// stores: &BTreeMap<MagicSymbol, DerivedRelStore>,
// out: &DerivedRelStore,
// ) -> Result<()> {
// todo!()
// }
// }
//
// pub(crate) struct Triangles;
//
// impl AlgoImpl for Triangles {
// fn run(
// &mut self,
// tx: &SessionTx,
// rels: &[MagicAlgoRuleArg],
// opts: &BTreeMap<SmartString<LazyCompact>, Expr>,
// stores: &BTreeMap<MagicSymbol, DerivedRelStore>,
// out: &DerivedRelStore,
// ) -> Result<()> {
// todo!()
// }
// }
use std::collections::{BTreeMap, BTreeSet};
use anyhow::{anyhow, Result};
use rayon::prelude::*;
use smartstring::{LazyCompact, SmartString};
use crate::algo::AlgoImpl;
use crate::data::expr::Expr;
use crate::data::program::{MagicAlgoRuleArg, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::derived::DerivedRelStore;
use crate::runtime::transact::SessionTx;
pub(crate) struct ClusteringCoefficients;
impl AlgoImpl for ClusteringCoefficients {
fn run(
&mut self,
tx: &SessionTx,
rels: &[MagicAlgoRuleArg],
_opts: &BTreeMap<SmartString<LazyCompact>, Expr>,
stores: &BTreeMap<MagicSymbol, DerivedRelStore>,
out: &DerivedRelStore,
) -> Result<()> {
let edges = rels
.get(0)
.ok_or_else(|| anyhow!("'clustering_coefficients' requires edges relation"))?;
let (graph, indices, _) = edges.convert_edge_to_graph(true, tx, stores)?;
let graph: Vec<BTreeSet<usize>> =
graph.into_iter().map(|e| e.into_iter().collect()).collect();
let coefficients = clustering_coefficients(&graph);
for (idx, (cc, n_triangles, degree)) in coefficients.into_iter().enumerate() {
out.put(
Tuple(vec![
indices[idx].clone(),
DataValue::from(cc),
DataValue::from(n_triangles as i64),
DataValue::from(degree as i64),
]),
0,
);
}
Ok(())
}
}
fn clustering_coefficients(graph: &[BTreeSet<usize>]) -> Vec<(f64, usize, usize)> {
graph
.par_iter()
.map(|edges| {
let degree = edges.len();
if degree < 2 {
(0., 0, degree)
} else {
let n_triangles = edges
.iter()
.map(|e_src| {
edges
.iter()
.filter(|e_dst| e_src > e_dst && graph[*e_src].contains(*e_dst))
.count()
})
.sum();
let cc = 2. * n_triangles as f64 / ((degree as f64) * ((degree as f64) - 1.));
(cc, n_triangles, degree)
}
})
.collect()
}

Loading…
Cancel
Save