79 lines
2.0 KiB
Cython
79 lines
2.0 KiB
Cython
# cython: cdivision=True
|
|
# cython: boundscheck=False
|
|
# cython: nonecheck=False
|
|
# cython: wraparound=False
|
|
cimport numpy as cnp
|
|
import numpy as np
|
|
cnp.import_array()
|
|
|
|
def argmin2(cnp.double_t[:] array):
|
|
"""Return the index of the 2nd smallest value in an array.
|
|
|
|
Parameters
|
|
----------
|
|
array : array
|
|
The array to process.
|
|
|
|
Returns
|
|
-------
|
|
min_idx2 : int
|
|
The index of the second smallest value.
|
|
"""
|
|
cdef cnp.float64_t min1 = np.inf
|
|
cdef cnp.float64_t min2 = np.inf
|
|
cdef Py_ssize_t min_idx1 = 0
|
|
cdef Py_ssize_t min_idx2 = 0
|
|
cdef Py_ssize_t i = 0
|
|
cdef Py_ssize_t n = array.shape[0]
|
|
|
|
for i in range(n):
|
|
x = array[i]
|
|
if x < min1:
|
|
min2 = min1
|
|
min_idx2 = min_idx1
|
|
min1 = x
|
|
min_idx1 = i
|
|
elif x > min1 and x < min2:
|
|
min2 = x
|
|
min_idx2 = i
|
|
i += 1
|
|
|
|
return min_idx2
|
|
|
|
|
|
def cut_cost(cut, W):
|
|
"""Return the total weight of crossing edges in a bi-partition.
|
|
|
|
Parameters
|
|
----------
|
|
cut : array
|
|
A array of booleans. Elements set to `True` belong to one
|
|
set.
|
|
W : array
|
|
The weight matrix of the graph.
|
|
|
|
Returns
|
|
-------
|
|
cost : float
|
|
The total weight of crossing edges.
|
|
"""
|
|
cdef cnp.ndarray[cnp.uint8_t, cast = True] cut_mask = np.array(cut)
|
|
cdef Py_ssize_t num_rows, num_cols
|
|
cdef cnp.int32_t row, col
|
|
cdef cnp.int32_t[:] indices = W.indices
|
|
cdef cnp.int32_t[:] indptr = W.indptr
|
|
cdef cnp.double_t[:] data = W.data.astype(np.double)
|
|
cdef cnp.int32_t row_index
|
|
cdef cnp.double_t cost = 0
|
|
|
|
num_rows = W.shape[0]
|
|
num_cols = W.shape[1]
|
|
|
|
for col in range(num_cols):
|
|
for row_index in range(indptr[col], indptr[col + 1]):
|
|
row = indices[row_index]
|
|
if cut_mask[row] != cut_mask[col]:
|
|
cost += data[row_index]
|
|
|
|
return cost * 0.5
|