80 const std::vector<
const tatami::Matrix<Value_, Index_>*>& representatives,
81 const std::vector<const Label_*>& labels,
84 size_t nrefs = representatives.size();
85 if (nrefs != labels.size()) {
86 throw std::runtime_error(
"'representatives' and 'labels' should have the same length");
89 throw std::runtime_error(
"'representatives' should contain at least one entry");
91 size_t ngenes = representatives.front()->nrow();
94 for (
size_t r = 0; r < nrefs; ++r) {
95 const auto& current = *representatives[r];
97 size_t nrows = current.nrow();
98 if (nrows != ngenes) {
99 throw std::runtime_error(
"all entries of 'representatives' should have the same number of rows");
102 size_t ncols = current.ncol();
104 auto curlab = labels[r];
105 nlabels = std::max(nlabels,
static_cast<size_t>(*std::max_element(curlab, curlab + ncols)) + 1);
110 std::vector<std::vector<std::pair<bool, Index_> > > labels_to_index(nrefs);
111 for (
size_t r = 0; r < nrefs; ++r) {
112 auto& current = labels_to_index[r];
113 current.resize(nlabels);
114 size_t ncols = representatives[r]->ncol();
115 auto curlab = labels[r];
117 for (
size_t c = 0; c < ncols; ++c) {
118 auto& info = current[curlab[c]];
120 throw std::runtime_error(
"each label should correspond to no more than one column in each reference");
128 for (
auto& x : output) {
132 int actual_number = options.
number;
133 if (actual_number < 0) {
136 if (actual_number >
static_cast<int>(ngenes)) {
137 actual_number = ngenes;
141 std::vector<std::pair<Label_, Label_> > pairs;
143 std::set<std::pair<Label_, Label_> > pairs0;
144 for (
size_t r = 0; r < nrefs; ++r) {
145 size_t ncols = representatives[r]->ncol();
146 auto curlab = labels[r];
147 for (
size_t c1 = 0; c1 < ncols; ++c1) {
148 for (
size_t c2 = 0; c2 < c1; ++c2) {
149 pairs0.emplace(curlab[c1], curlab[c2]);
153 pairs.insert(pairs.end(), pairs0.begin(), pairs0.end());
156 tatami::parallelize([&](
int,
size_t start,
size_t len) {
157 std::vector<std::pair<Value_, Index_> > sorter(ngenes);
158 std::vector<Value_> rbuffer(ngenes), lbuffer(ngenes);
159 std::vector<std::shared_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > > rextractors(nrefs), lextractors(nrefs);
161 for (
size_t p = start, end = start + len; p < end; ++p) {
162 auto curleft = pairs[p].first;
163 auto curright = pairs[p].second;
165 for (
size_t g = 0; g < ngenes; ++g) {
167 sorter[g].second = g;
170 for (
size_t i = 0; i < nrefs; ++i) {
171 const auto& curavail = labels_to_index[i];
172 auto lcol = curavail[curleft];
173 auto rcol = curavail[curright];
174 if (!lcol.first || !rcol.first) {
179 auto& lext = lextractors[i];
181 lext = representatives[i]->dense_column();
183 auto lptr = lext->fetch(lcol.second, lbuffer.data());
185 auto& rext = rextractors[i];
187 rext = representatives[i]->dense_column();
189 auto rptr = rext->fetch(rcol.second, rbuffer.data());
191 for (
size_t g = 0; g < ngenes; ++g) {
192 sorter[g].first += lptr[g] - rptr[g];
199 for (
int flip = 0; flip < 2; ++flip) {
201 for (
auto& s : sorter) {
207 std::partial_sort(sorter.begin(), sorter.begin() + actual_number, sorter.end());
209 std::vector<Index_> stuff;
210 stuff.reserve(actual_number);
211 for (
int g = 0; g < actual_number && sorter[g].first < 0; ++g) {
212 stuff.push_back(sorter[g].second);
216 output[curleft][curright] = std::move(stuff);
218 output[curright][curleft] = std::move(stuff);