11# Hobohm I
22# ========
33
4+ const _HOBOHM_THREADS = """ The `threads` keyword argument (default: `false`) controls
5+ whether the inner scan over candidate cluster members runs in parallel when worker threads
6+ are available."""
7+
48"""
5- Fill `cluster` and `clustersize` vectors. They are assumed to be empty (only
6- zeroes) and their length must be equal to the number of elements to cluster.
7- `within_cluster` is a predicate that takes two items and a `threshold` and
8- returns `true` if they should belong to the same cluster. `threshold` is passed
9- as the last argument to `within_cluster`. The number of elements is stored in
10- `n_items`.
9+ Fill `cluster` with the Hobohm I assignments and return the number of clusters.
10+ `cluster` is assumed to be empty (only zeroes) and its length must be equal to
11+ the number of elements to cluster. `within_cluster` is a predicate that takes
12+ two items and a `threshold` and returns `true` if they should belong to the
13+ same cluster. `threshold` is passed as the last argument to `within_cluster`.
14+ The number of elements is stored in `n_items`.
1115"""
1216function _fill_hobohmI! (
17+ scan_function:: Function ,
1318 within_cluster:: Function ,
1419 cluster:: Vector{Int} ,
15- clustersize:: Vector{Int} ,
1620 items:: AbstractVector ,
1721 threshold,
1822)
@@ -22,22 +26,70 @@ function _fill_hobohmI!(
2226 if cluster[i] == 0
2327 cluster_id += 1
2428 cluster[i] = cluster_id
25- clustersize[cluster_id] += 1
2629 ref_item = items[i]
27- for j = (i+ 1 ): n_items
28- if cluster[j] == 0 && within_cluster (ref_item, items[j], threshold)
29- cluster[j] = cluster_id
30- clustersize[cluster_id] += 1
31- end
32- end
30+ scan_function (
31+ within_cluster,
32+ cluster,
33+ items,
34+ ref_item,
35+ threshold,
36+ cluster_id,
37+ i + 1 ,
38+ n_items,
39+ )
3340 end
3441 end
3542 @inbounds if cluster[n_items] == 0
3643 cluster_id += 1
3744 cluster[n_items] = cluster_id
38- clustersize[cluster_id] += 1
3945 end
40- resize! (clustersize, cluster_id)
46+ cluster_id
47+ end
48+
49+ function _scan_hobohmI_serial! (
50+ within_cluster:: Function ,
51+ cluster:: Vector{Int} ,
52+ items:: AbstractVector ,
53+ ref_item,
54+ threshold,
55+ cluster_id:: Int ,
56+ first_candidate:: Int ,
57+ last_candidate:: Int ,
58+ )
59+ @inbounds for j = first_candidate: last_candidate
60+ if cluster[j] == 0 && within_cluster (ref_item, items[j], threshold)
61+ cluster[j] = cluster_id
62+ end
63+ end
64+ end
65+
66+ function _scan_hobohmI_threaded! (
67+ within_cluster:: Function ,
68+ cluster:: Vector{Int} ,
69+ items:: AbstractVector ,
70+ ref_item,
71+ threshold,
72+ cluster_id:: Int ,
73+ first_candidate:: Int ,
74+ last_candidate:: Int ,
75+ )
76+ Threads. @threads for j = first_candidate: last_candidate
77+ @inbounds if cluster[j] == 0 && within_cluster (ref_item, items[j], threshold)
78+ cluster[j] = cluster_id
79+ end
80+ end
81+ end
82+
83+ function _fill_hobohmI! (
84+ within_cluster:: Function ,
85+ cluster:: Vector{Int} ,
86+ items:: AbstractVector ,
87+ threshold;
88+ threads:: Bool = true ,
89+ )
90+ use_threads = threads && Threads. nthreads () > 1
91+ scan_function = ifelse (use_threads, _scan_hobohmI_threaded!, _scan_hobohmI_serial!)
92+ _fill_hobohmI! (scan_function, within_cluster, cluster, items, threshold)
4193end
4294
4395"""
@@ -53,42 +105,81 @@ function _get_sequence_weight(clustersize, cluster)
53105 Weights (sequence_weight, Float64 (length (clustersize)))
54106end
55107
108+ function _hobohmI (within_cluster:: Function , items:: AbstractVector , threshold; threads:: Bool )
109+ n = length (items)
110+ cluster = zeros (Int, n)
111+ clustersize = zeros (Int, n)
112+ nclusters = _fill_hobohmI! (within_cluster, cluster, items, threshold; threads = threads)
113+ resize! (clustersize, nclusters)
114+ @inbounds for i = 1 : n
115+ clustersize[cluster[i]] += 1
116+ end
117+ Clusters (clustersize, cluster, _get_sequence_weight (clustersize, cluster))
118+ end
119+
56120"""
57- `hobohmI(within_cluster, items, threshold)`
121+ `hobohmI(within_cluster, items, threshold; threads=false )`
58122
59123Cluster `items` using the Hobohm I algorithm from Hobohm et al. `within_cluster`
60124is a predicate that receives two elements and `threshold` and returns `true` when
61- they should be clustered together.
125+ they should be clustered together. $_HOBOHM_THREADS
62126
63127# References
64128
65129 - [Hobohm, Uwe, et al. "Selection of representative protein data sets."
66130 Protein Science 1.3 (1992): 409-417.](@cite 10.1002/pro.5560010313)
67131"""
68- function hobohmI (within_cluster:: Function , items:: AbstractVector , threshold)
69- n = length (items)
70- cluster = zeros (Int, n)
71- clustersize = zeros (Int, n)
72- _fill_hobohmI! (within_cluster, cluster, clustersize, items, threshold)
73- Clusters (clustersize, cluster, _get_sequence_weight (clustersize, cluster))
132+ function hobohmI (
133+ within_cluster:: Function ,
134+ items:: AbstractVector ,
135+ threshold;
136+ threads:: Bool = false ,
137+ )
138+ _hobohmI (within_cluster, items, threshold; threads = threads)
139+ end
140+
141+ function hobohmI (
142+ :: typeof (percentidentity),
143+ items:: AbstractVector ,
144+ threshold;
145+ threads:: Bool = false ,
146+ )
147+ _hobohmI (percentidentity, items, threshold; threads = threads)
74148end
75149
76150"""
77- `hobohmI(within_cluster, msa, threshold)`
151+ `hobohmI(within_cluster, msa, threshold; threads=false )`
78152
79153This method allows clustering the aligned sequences in `msa` using the
80154`within_cluster` predicate. It converts the alignment into a vector of
81- residue sequences and forwards the call to the general method.
155+ residue sequences and forwards the call to the general method. $_HOBOHM_THREADS
82156"""
83- function hobohmI (within_cluster:: Function , msa:: AbstractMatrix{Residue} , threshold)
157+ function hobohmI (
158+ within_cluster:: Function ,
159+ msa:: AbstractMatrix{Residue} ,
160+ threshold;
161+ threads:: Bool = false ,
162+ )
163+ aln = getresiduesequences (msa)
164+ hobohmI (within_cluster, aln, threshold; threads = threads)
165+ end
166+
167+ function hobohmI (
168+ :: typeof (percentidentity),
169+ msa:: AbstractMatrix{Residue} ,
170+ threshold;
171+ threads:: Bool = false ,
172+ )
84173 aln = getresiduesequences (msa)
85- hobohmI (within_cluster , aln, threshold)
174+ hobohmI (percentidentity , aln, threshold; threads = threads )
86175end
87176
88177"""
89- `hobohmI(msa, threshold)`
178+ `hobohmI(msa, threshold; threads=false )`
90179
91180This method allows to cluster the sequences contained in `msa` using
92- `percentidentity` as the clustering predicate.
181+ `percentidentity` as the clustering predicate. $_HOBOHM_THREADS
93182"""
94- hobohmI (msa:: AbstractMatrix{Residue} , threshold) = hobohmI (percentidentity, msa, threshold)
183+ function hobohmI (msa:: AbstractMatrix{Residue} , threshold; threads:: Bool = false )
184+ hobohmI (percentidentity, msa, threshold; threads = threads)
185+ end
0 commit comments