From d256dca14e8cd21b2db3694217af8395501bd74a Mon Sep 17 00:00:00 2001 From: boris-kz Date: Thu, 26 Dec 2024 22:11:43 -0500 Subject: [PATCH] edits with Chee --- frame_2D_alg/deprecated/24.12.py | 24 ++++++- .../vectorize_edge_blob/agg_recursion.py | 35 +++++---- frame_2D_alg/vectorize_edge_blob/vect_edge.py | 72 +++++++++---------- 3 files changed, 77 insertions(+), 54 deletions(-) diff --git a/frame_2D_alg/deprecated/24.12.py b/frame_2D_alg/deprecated/24.12.py index eb7195d6e..8a7366a7e 100644 --- a/frame_2D_alg/deprecated/24.12.py +++ b/frame_2D_alg/deprecated/24.12.py @@ -376,7 +376,29 @@ def sum_tft(HE, He, rev=0, fc=0): else: HE.tft = deepcopy(He.tft) # init empty - +''' if nest: # root_ in distance-layered cluster, or for Ns only, graph membership is still exclusive? root = [root] + (node_[0].root if isinstance(node_[0].root, list) else [node_[0].root]) else: root = root +''' +def append_(HE, He): # unpack HE lft tree down to He.fd_ and append He, or sum if fork exists, if He.fd_ + + fork = root = HE + add = 1 + if He.fd_: + for fd in He.fd_: # unpack top-down, each fd was assigned by corresponding level of roots + if len(fork.lft) > fd: + root = fork; fork = fork.lft[fd] # keep unpacking + else: + He = He.copy_(); fork.lft += [He]; add = 0 # fork was empty, init with He + break + if add: + fork.add_tree(He, root) # add in fork initialized by feedback + else: + HE.lft += [He] # if fd_ is empty, we just need to append it? + + He.root = root + fork.Et += He.Et + if not fork.tft: + fork.tft = deepcopy(He.tft) # if init from sum mlink_ + diff --git a/frame_2D_alg/vectorize_edge_blob/agg_recursion.py b/frame_2D_alg/vectorize_edge_blob/agg_recursion.py index b5a6d4e98..4a73540f3 100644 --- a/frame_2D_alg/vectorize_edge_blob/agg_recursion.py +++ b/frame_2D_alg/vectorize_edge_blob/agg_recursion.py @@ -5,7 +5,7 @@ from functools import reduce from frame_blobs import frame_blobs_root, intra_blob_root, imread from comp_slice import comp_latuple, comp_md_ -from vect_edge import feedback, comp_node_, comp_link_, sum2graph, get_rim, CH, CG, ave, ave_d, ave_L, vectorize_root, comp_area, extend_box, val_ +from vect_edge import feedback, comp_node_, comp_link_, sum2graph, get_rim, CH, CG, ave, ave_L, vectorize_root, comp_area, extend_box, val_ ''' Cross-compare and cluster Gs within a frame, potentially unpacking their node_s first, alternating agglomeration and centroid clustering. @@ -22,29 +22,34 @@ def cross_comp(root): # breadth-first node_,link_ cross-comp, connect.clusterin N_,L_,Et = comp_node_(root.subG_) # cross-comp exemplars, extrapolate to their node_s # mfork if val_(Et, fo=1) > 0: - mlay = CH().add_tree([L.derH for L in L_]); mlay.fd_=[]; root.derH.append_(mlay) + H = root.derH # for both forks + mlay = CH().add_tree([L.derH for L in L_]); mlay.root = H; H.Et += mlay.Et; H.lft = [mlay]; H.tft = mlay.tft pL_ = {l for n in N_ for l,_ in get_rim(n, fd=0)} if len(pL_) > ave_L: cluster_N_([root], pL_, fd=0) # optional divisive clustering, calls centroid and higher connect.clustering # dfork if val_(Et, mEt=Et,fo=1) > 0: # same root for L_, root.link_ was compared in root-forming for alt clustering - for L in L_: - L.extH, L.root, L.mL_t, L.rimt, L.aRad, L.visited_, L.Et = CH(), root, [[],[]], [[],[]], 0, [L], copy(L.derH.Et) + convert_L_(L_,root) lN_,lL_,dEt = comp_link_(L_,Et) if val_(dEt, mEt=Et, fo=1) > 0: - dlay = CH().add_tree([L.derH for L in lL_]); dlay.fd_= []; root.derH.append_(dlay) + dlay = CH().add_tree([L.derH for L in lL_]); dlay.root = H; H.Et += dlay.Et; H.lft += [dlay] plL_ = {l for n in lN_ for l,_ in get_rim(n, fd=1)} if len(plL_) > ave_L: cluster_N_([root], plL_, fd=1) feedback(root) # add root derH to higher roots derH +def convert_L_(L_, root): + for L in L_: + L.extH, L.mL_t, L.rimt, L.aRad, L.visited_ = CH(), [[],[]], [[],[]], 0, [L] + L.root = [L.root,root]; L.Et = copy(L.derH.Et) # convert to root_ + def cluster_N_(root_, L_, fd, nest=0): # top-down segment L_ by >ave ratio of L.dists - L_ = sorted(L_, key=lambda x: x.dist, reverse=True) # shorter links - _L = L_[0] - N_, et = _L.nodet, _L.derH.Et + L_ = sorted(L_, key=lambda x: x.dist, reverse=True) # current and shorter links + for n in [n for l in L_ for n in l.nodet]: n.fin = 0 + _L = L_[0]; N_, et = _L.nodet, _L.derH.Et # current dist segment: for i, L in enumerate(L_[1:], start=1): # long links first rel_dist = _L.dist / L.dist # >1 @@ -53,8 +58,7 @@ def cluster_N_(root_, L_, fd, nest=0): # top-down segment L_ by >ave ratio of L else: break # terminate contiguous-distance segment G_ = [] - min_dist = _L.dist; N_ = {N_} - for N in N_: N.fin = 0 + min_dist = _L.dist; N_ = {*N_} for N in N_: # cluster current distance segment if N.fin: continue _eN_, node_,link_, et, = [N], [],[], np.zeros(4) @@ -68,18 +72,19 @@ def cluster_N_(root_, L_, fd, nest=0): # top-down segment L_ by >ave ratio of L if L.dist >= min_dist: link_+=[L]; et+=L.derH.Et _eN_ = [] - for n in {eN_}: + for n in {*eN_}: n.fin = 0; _eN_ += [n] - G = sum2graph(root_, [list({node_}),list({link_}), et, min_dist], fd, nest) + G_ += [sum2graph(root_, [list({*node_}),list({*link_}), et, min_dist], fd, nest)] # higher root_ assign to all sub_G nodes - sub_L_ = {l for n in node_ for l,_ in get_rim(n,fd) if l.dist < min_dist} + for G in G_: # breadth-first + sub_L_ = {l for n in G.node_ for l,_ in get_rim(n,fd) if l.dist < min_dist} if len(sub_L_) > ave_L: Et = np.sum([sL.derH.Et for sL in sub_L_],axis=0); Et[3]+=nest if val_(Et, fo=1) > 0: cluster_N_(root_+[G], sub_L_, fd, nest+1) # sub-cluster shorter links, nest in G.subG_ - G_ += [G] + # root_ += [root] / dist segment root_[-1].subG_ = G_ - cluster_C_(root_[-1]) # root per higher dist segment + cluster_C_(root_[-1]) ''' Hierarchical clustering should alternate between two phases: generative via connectivity and compressive via centroid. diff --git a/frame_2D_alg/vectorize_edge_blob/vect_edge.py b/frame_2D_alg/vectorize_edge_blob/vect_edge.py index 18ca1fa39..83095b2b7 100644 --- a/frame_2D_alg/vectorize_edge_blob/vect_edge.py +++ b/frame_2D_alg/vectorize_edge_blob/vect_edge.py @@ -72,11 +72,11 @@ def __bool__(H): return bool(H.tft) # empty CH def copy_(He, root=None, rev=0, fc=0, i=None): # comp direction may be reversed to -1 - if i: # from other source - C = He; C.lft = []; C.tft=[]; C.fd_=copy(i.fd_); C.root=root; C.node_=copy(i.node_) - else: # from self - C = CH(fd_=copy(He.fd_), root=root, node_=copy(He.node_)) - C.Et = i.Et * -1 if (fc and rev) else copy(i.Et) + if i: # reuse self + C = He; He = i; C.lft = []; C.tft=[]; C.root=root; C.node_=copy(i.node_) + else: # init new C + C = CH(root=root, node_=copy(He.node_), fd_=copy(He.fd_)) + C.Et = He.Et * -1 if (fc and rev) else copy(He.Et) for fd, tt in enumerate(He.tft): # nested array tuples C.tft += [tt * -1 if rev and (fd or fc) else deepcopy(tt)] @@ -98,7 +98,9 @@ def add_tree(HE, He_, root=None, rev=0, fc=0): # rev = dir==-1, unpack derH tre for F, f in zip_longest(HE.lft, He.lft, fillvalue=None): # CH forks if f: # not bottom layer if F: F.add_tree(f,rev,fc) # unpack both forks - else: HE.append_(f.copy_) + else: + f.root=HE; HE.lft += [f]; HE.Et += f.Et + if not HE.tft: HE.tft = f.tft # init with mfork? HE.node_ += [node for node in He.node_ if node not in HE.node_] # empty in CL derH? HE.Et += He.Et * -1 if rev and fc else He.Et @@ -106,24 +108,6 @@ def add_tree(HE, He_, root=None, rev=0, fc=0): # rev = dir==-1, unpack derH tre HE.copy_(root,rev,fc, i=He) return HE - def append_(HE, He): # unpack HE lft tree down to He.fd_ and append He, or sum if fork exists, if He.fd_ - - fork = root = HE - add = 1 - for fd in He.fd_: # unpack top-down, each fd was assigned by corresponding level of roots - if len(fork.lft) > fd: - root = fork - fork = fork.lft[fd] - else: - fork.lft += [He.copy_]; add = 0 # fork was empty, init with He - break - if add: - fork.add_tree(He, root) # add in fork initialized by feedback - He.root = root - fork.Et += He.Et - if not fork.tft: - fork.tft = deepcopy(He.tft) # if init from sum mlink_ - def comp_tree(_He, He, rn, root, dir=1): # unpack derH trees down to numericals and compare them _d_t, d_t = _He.tft[1], He.tft[1] # comp_tft: @@ -283,7 +267,8 @@ def cluster_PP_(edge, fd): edge.subG_ = N_ edge.link_ = L_ if val_(Et, fo=1) > 0: # cancel by borrowing d? - mlay = CH().add_tree([L.derH for L in L_]); mlay.fd_=[]; edge.derH.append_(mlay) + mlay = CH().add_tree([L.derH for L in L_]) + H = edge.derH; mlay.root=H; H.Et += mlay.Et; H.lft = [mlay]; H.tft = mlay.tft # init with mfork if len(N_) > ave_L: cluster_PP_(edge, fd=0) if val_(Et, mEt=Et, fo=1) > 0: # likely not from the same links @@ -292,7 +277,8 @@ def cluster_PP_(edge, fd): # comp dPP_: lN_,lL_,dEt = comp_link_(L_, Et) if val_(dEt, fo=1) > 0: - dlay = CH().add_tree([L.derH for L in lL_]); dlay.fd_= []; edge.derH.append_(dlay) + dlay = CH().add_tree([L.derH for L in lL_]) + H = edge.derH; dlay.root=H; H.Et += dlay.Et; H.lft += [dlay] if len(lN_) > ave_L: cluster_PP_(edge, fd=1) @@ -420,19 +406,19 @@ def comp_N(_N,N, rn, angle=None, dist=None, dir=1): # dir if fd, Link.derH=dH, d_t = np.array([d_t, dLat, dVer], dtype=object) Et += np.array([et1[0]+et2[0], et1[1]+et2[1], 2, 0]) # same olp? - derH = CH(fd_=[fd], tft=[m_t,d_t], Et=Et) + lay = CH(fd_=[fd], tft=[m_t,d_t], Et=Et) if _N.derH and N.derH: - dderH = _N.derH.comp_tree(N.derH, rn, root=derH) # comp shared layers - derH.append_(dderH) + derH = _N.derH.comp_tree(N.derH, rn, root=lay) # comp shared layers + lay.Et += derH.Et; lay.lft = [derH]; lay.tft = derH.tft # this is mfork? # spec: comp_node_(node_|link_), combinatorial, node_ nested / rng-)agg+? - Et = copy(derH.Et) + Et = copy(lay.Et) if not fd and _N.altG and N.altG: # not for CL, eval M? alt_Link = comp_N(_N.altG, N.altG, _N.altG.Et[2]/N.altG.Et[2]) # no angle,dist, init alternating PPds | dPs? - derH.altH = alt_Link.derH - Et += derH.altH.Et - Link = CL(nodet=[_N,N],derH=derH, yx=np.add(_N.yx,N.yx)/2, angle=angle,dist=dist,box=extend_box(N.box,_N.box)); derH.root=Link + lay.altH = alt_Link.derH + Et += lay.altH.Et + Link = CL(nodet=[_N,N], derH=lay, yx=np.add(_N.yx,N.yx)/2, angle=angle,dist=dist,box=extend_box(N.box,_N.box)) + lay.root = Link if val_(Et) > 0: - derH.root = Link for rev, node in zip((0,1), (N,_N)): # reverse Link direction for _N if fd: node.rimt[1-rev] += [(Link,rev)] # opposite to _N,N dir else: node.rim += [(Link,dir)] @@ -465,12 +451,12 @@ def sum2graph(root, grapht, fd, nest): # sum node and link params into graph, a graph.Et += N.Et * icoef ** 2 # deeper, lower weight if nest: if nest==1: N.root = [N.root] # initial conversion - N.root += [graph + root] # root_ in distance-layered cluster_N_ + N.root += root + [graph] # root is root_ in distance-layered cluster_N_ else: N.root = graph # single root # sum link_ derH: derLay = CH().add_tree([link.derH for link in link_],root=graph) # root added in copy_ within add_tree if derH: - derH.fd_=[]; derLay.append_(derH) + derLay.lft += [derH]; derLay.Et += derH.Et graph.derH = derLay L = len(node_) yx = np.divide(yx,L); graph.yx = yx @@ -489,11 +475,21 @@ def sum2graph(root, grapht, fd, nest): # sum node and link params into graph, a feedback(graph) # recursive root.derH.add_fork(graph.derH) return graph -def feedback(node): # propagate derH to higher roots +def feedback(node): # propagate node.derH to higher roots while node.root: root = node.root[-1] if isinstance(node.root,list) else node.root # root_ in distance-layered cluster - root.derH.append_(node.derH) # root.derH.lft += node.derH + lowH = addH = root.derH + add = 1 + for fd in addH.fd_: # unpack top-down, each fd was assigned by corresponding level of roots + if len(addH.lft) > fd: + addH = lowH; lowH = lowH.lft[fd] # keep unpacking + else: + lowH.lft += [addH.copy_()]; add = 0 # fork was empty, init with He + break + if add: # add in fork initialized by prior feedback + lowH.add_tree(addH, root) + node = root def sum_G_(node_):