import * as $I from "./interfaces" ; import { TypedGraph } from "@/core/typed/TypedGraph" ; import { ITypedNode } from "@/core/typed/TypedNode" ; export const sortFuncs = { asc : ( se1 , se2 ) => se1 . sim - se2 . sim , desc : ( se1 , se2 ) => se2 . sim - se1 . sim , } ; export const cutFuncs = { above : ( sim , threshold ) => sim >= threshold , below : ( sim , threshold ) => sim <= threshold , } ; export function sim ( algo , a , b ) { return algo ( a , b ) ; } description param algo param s param t param cfg export function simSource ( algo , s , t , cfg = { } ) { const sort = cfg . sort || sortFuncs . desc ; const cutFunc = cfg . cutFunc || cutFuncs . above ; let result = [ ] ; const start = t [ s ] ; for ( let [ k , v ] of Object . entries ( t ) ) { if ( k === s ) { continue ; } const sim = algo ( start , v ) ; if ( cfg . cutoff == null || cutFunc ( sim . sim , cfg . cutoff ) ) { result . push ( { from : s , to : k , ... sim } ) ; } } result . sort ( sort ) ; if ( cfg . knn != null && cfg . knn <= result . length ) { result = result . slice ( 0 , cfg . knn ) ; } return result ; } description param algo param s param cfg export function simPairwise ( algo , s , cfg = { } ) { const sort = cfg . sort || sortFuncs . desc ; const cutFunc = cfg . cutFunc || cutFuncs . above ; let result = [ ] ; const keys = Object . keys ( s ) ; for ( let i in keys ) { for ( let j = 0 ; j < + i ; j ++ ) { const from = keys [ i ] ; const to = keys [ j ] ; if ( from === to ) { continue ; } const sim = algo ( s [ keys [ i ] ] , s [ keys [ j ] ] , i , j ) ; if ( cfg . cutoff == null || cutFunc ( sim . sim , cfg . cutoff ) ) { result . push ( { from , to , ... sim } ) ; } } } result . sort ( sort ) ; if ( cfg . knn != null && cfg . knn <= result . length ) { result = result . slice ( 0 , cfg . knn ) ; } return result ; } description description param algo param s1 param s2 param cfg returns export function simSubsets ( algo , s1 , s2 , cfg = { } ) { const sort = cfg . sort || sortFuncs . desc ; const cutFunc = cfg . cutFunc || cutFuncs . above ; let result = [ ] ; const keys1 = Object . keys ( s1 ) ; const keys2 = Object . keys ( s2 ) ; for ( let i in keys1 ) { let subRes = [ ] ; for ( let j in keys2 ) { const from = keys1 [ i ] ; const to = keys2 [ j ] ; if ( from === to ) { continue ; } const sim = algo ( s1 [ keys1 [ i ] ] , s2 [ keys2 [ j ] ] ) ; if ( cfg . cutoff == null || cutFunc ( sim . sim , cfg . cutoff ) ) { subRes . push ( { from , to , ... sim } ) ; } } subRes . sort ( sort ) ; if ( cfg . knn != null && cfg . knn <= subRes . length ) { subRes = subRes . slice ( 0 , cfg . knn ) ; } result = result . concat ( subRes ) ; } return result . sort ( sort ) ; } description param algo param s param cfg returns todo export function knnNodeArray ( algo , s , cfg ) { const sort = cfg . sort || sortFuncs . desc ; const c = cfg . cutoff || 0 ; const topK = [ ] ; const dupes = { } ; for ( let node of Object . keys ( s ) ) { const topKEntries = simSource ( algo , node , s , { knn : cfg . knn || 1 , sort : cfg . sort , } ) ; topKEntries . forEach ( e => { if ( c == null || e . sim < c ) { return ; } if ( ! cfg . dup && ( ( dupes [ e . from ] && dupes [ e . from ] [ e . to ] ) || ( dupes [ e . to ] && dupes [ e . to ] [ e . from ] ) ) ) { return ; } topK . push ( e ) ; dupes [ e . from ] = dupes [ e . from ] || { } ; dupes [ e . from ] [ e . to ] = true ; } ) ; } return topK . sort ( sort ) ; } param algo param s param cfg export function knnNodeDict ( algo , s , cfg ) { const sort = cfg . sort || sortFuncs . desc ; const c = cfg . cutoff || 0 ; const topK = { } ; for ( let node of Object . keys ( s ) ) { const topKEntries = simSource ( algo , node , s , { knn : cfg . knn || 1 , sort : cfg . sort , } ) ; topKEntries . forEach ( e => { if ( c == null || e . sim < c ) { return ; } delete e . from ; topK [ node ] = topK [ node ] || [ ] ; topK [ node ] . push ( e ) ; } ) ; for ( let arr of Object . values ( topK ) ) { arr . sort ( sort ) ; } } return topK ; } description description param g param algo param cfg returns todo todo export function viaSharedPrefs ( g , algo , cfg ) { const sort = cfg . sort || sortFuncs . desc ; const cutoff = cfg . co == null ? 1e-6 : cfg . co ; const cutFunc = cfg . cutFunc || cutFuncs . above ; const sims = [ ] ; const t1Set = g . getNodesT ( cfg . t1 ) ; const t2Set = g . getNodesT ( cfg . t2 ) ; const prefCache = new Map < string , Set < ITypedNode > > ( ) ; for ( let [ t1Name , t1Node ] of t1Set . entries ( ) ) { for ( let [ t2Name , t2Node ] of t2Set . entries ( ) ) { let prefSet1 , prefSet2 ; if ( prefCache . get ( t1Node . id ) ) { prefSet1 = prefCache . get ( t1Node . id ) ; } else { prefSet1 = g [ cfg . d1 ] ( t1Node , cfg . e1 . toUpperCase ( ) ) ; prefCache . set ( t1Node . id , prefSet1 ) ; } if ( prefCache . get ( t2Node . id ) ) { prefSet2 = prefCache . get ( t2Node . id ) ; } else { prefSet2 = g [ cfg . d2 ] ( t2Node , cfg . e2 . toUpperCase ( ) ) ; prefCache . set ( t2Node . id , prefSet2 ) ; } if ( ! prefSet1 || ! prefSet2 || prefSet1 . size === 0 || prefSet2 . size === 0 ) { continue ; } const sim = algo ( prefSet1 , prefSet2 ) ; if ( cutFunc ( sim . sim , cutoff ) ) { sims . push ( { from : t1Name , to : t2Name , ... sim } ) ; } } } return sims . sort ( sort ) ; } description param a param b export function getBsNotInA ( a , b ) { let result = new Set < ITypedNode > ( ) ; let sa = new Set ( ) , sb = new Set ( ) ; for ( let e of a ) sa . add ( e . label ) ; for ( let e of b ) { if ( ! sa . has ( e . label ) ) { result . add ( e ) ; } } return result ; } description todo todo