static void so_sparse_matrix_add(so_sparse_entries_t matrix, int index, float value) { if (matrix.count == matrix.capacity) { int newCapacity = matrix.capacity * 2; if (newCapacity < 64) { newCapacity = 64; } so_sparse_entry_t[] newEntries = new so_sparse_entry_t[newCapacity]; for (int i = 0; i < matrix.count; i++) { newEntries[i] = matrix.entries[i]; } for (int i = matrix.count; i < newCapacity; i++) { newEntries[i] = new so_sparse_entry_t(-1, 0); } matrix.entries = newEntries; matrix.capacity = newCapacity; } int entryIndex = matrix.count++; matrix.entries[entryIndex].index = index; matrix.entries[entryIndex].value = value; }
public so_sparse_entries_t(int _capacity) { entries = new so_sparse_entry_t[_capacity]; for (int i = 0; i < _capacity; i++) { entries[i] = new so_sparse_entry_t(-1, 0); } capacity = _capacity; count = 0; }
static so_sparse_entry_t so_sparse_entry_set_get_or_add(so_sparse_entries_t set, int index) { if (set.count + 1 > set.capacity * 3 / 4) // leave some free space to avoid having many collisions { int newCapacity = set.capacity >= 64 ? set.capacity * 2 : 64; so_sparse_entry_t[] newEntries = new so_sparse_entry_t[newCapacity]; for (int i = 0; i < newCapacity; i++) { newEntries[i] = new so_sparse_entry_t(-1, 0); } for (int i = 0; i < set.capacity; i++) // rehash all old entries { if (set.entries[i].index != -1) { int hash_ = so_sparse_entry_hash(set.entries[i].index, newCapacity); while (newEntries[hash_].index != -1) // collisions { hash_ = (hash_ + 1) % newCapacity; } newEntries[hash_] = set.entries[i]; } } set.entries = newEntries; set.capacity = newCapacity; } int hash = so_sparse_entry_hash(index, set.capacity); while (set.entries[hash].index != -1) // collisions { if (set.entries[hash].index == index) { return(set.entries[hash]); // entry is already in the set } hash = (hash + 1) % set.capacity; } if (set.entries[hash].index == -1) // make new entry { set.entries[hash].index = index; set.entries[hash].value = 0.0f; set.count++; return(set.entries[hash]); } Debug.Assert(false); return(null); // shouldn't happen }
static so_sparse_entries_t so_matrix_At_times_A(float[] A, int[] sparseIndices, int maxRowIndices, int m, int n) { so_sparse_entries_t AtA = new so_sparse_entries_t((n / 16) * (n / 16)); // compute lower left triangle only since the result is symmetric for (int k = 0; k < m; k++) { int srcPtr = k * maxRowIndices; int indexPtr = k * maxRowIndices; for (int i = 0; i < maxRowIndices; i++) { int index_i = sparseIndices[indexPtr + i]; if (index_i < 0) { break; } float v = A[srcPtr + i]; //float *dstPtr = AtA + index_i * n; for (int j = 0; j < maxRowIndices; j++) { int index_j = sparseIndices[indexPtr + j]; if (index_j < 0) { break; } //dstPtr[index_j] += v * srcPtr[j]; int index = index_i * n + index_j; so_sparse_entry_t entry = so_sparse_entry_set_get_or_add(AtA, index); entry.value += v * A[srcPtr + j]; } } } // compaction step (make a compact array from the scattered hash set values) for (int i = 0, j = 0; i < AtA.capacity; i++) { if (AtA.entries[i].index != -1) { AtA.entries[j++] = AtA.entries[i]; } } // sort by index . this is a sparse matrix now so_sparse_matrix_sort(AtA); return(AtA); }