Skip to content

Commit

Permalink
#587, #588, #589 Optimization for DBSCAN, OPTICS, CURE (Python versio…
Browse files Browse the repository at this point in the history
…n). #586 KD-tree visualizer. #379 Balanced KD-tree to reduce complexity of search procedure.
  • Loading branch information
annoviko committed Feb 14, 2020
1 parent 4f4db71 commit d53287b
Show file tree
Hide file tree
Showing 13 changed files with 1,040 additions and 599 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ CHANGE NOTES FOR 0.10.0 (STARTED Jan 24, 2020), (RELEASED: Dev -)
------------------------------------------------------------------------

GENERAL CHANGES:
- Implemented KD-tree graphical visualizer `kdtree_visualizer` for KD-trees with 2-dimensional data (pyclustering.container.kdtree).
See: https://github.com/annoviko/pyclustering/issues/586

- Updated interface of each clustering algorithm in C/C++ pyclustering `cluster_data` is substituted by concrete classes (ccore.clst).
See: https://github.com/annoviko/pyclustering/issues/577

Expand Down
65 changes: 36 additions & 29 deletions ccore/include/pyclustering/nnet/hhn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,53 +48,60 @@ namespace pyclustering {
namespace nnet {


/*!
@class hnn_parameters hhn.hpp pyclustering/nnet/hhn.hpp
@brief Defines parameters of Hodgkin-Hixley Network.
*/
struct hnn_parameters {
public:
double m_nu = generate_uniform_random(-1.0, 1.0); /* Intrinsic noise */
double m_nu = generate_uniform_random(-1.0, 1.0); /**< Intrinsic noise. */

double m_gNa = 120.0 * (1.0 + 0.02 * m_nu); /* Maximal conductivity for sodium current */
double m_gK = 36.0 * (1.0 + 0.02 * m_nu); /* Maximal conductivity for potassium current */
double m_gL = 0.3 * (1.0 + 0.02 * m_nu); /* Maximal conductivity for leakage current */
double m_gNa = 120.0 * (1.0 + 0.02 * m_nu); /**< Maximal conductivity for sodium current. */
double m_gK = 36.0 * (1.0 + 0.02 * m_nu); /**< Maximal conductivity for potassium current. */
double m_gL = 0.3 * (1.0 + 0.02 * m_nu); /**< Maximal conductivity for leakage current. */

double m_vNa = 50.0; /* Reverse potential of sodium current [mV] */
double m_vK = -77.0; /* Reverse potential of potassium current [mV] */
double m_vL = -54.4; /* Reverse potantial of leakage current [mV] */
double m_vRest = -65.0; /* Rest potential [mV]. */
double m_vNa = 50.0; /**< Reverse potential of sodium current [mV]. */
double m_vK = -77.0; /**< Reverse potential of potassium current [mV]. */
double m_vL = -54.4; /**< Reverse potantial of leakage current [mV]. */
double m_vRest = -65.0; /**< Rest potential [mV]. */

double m_Icn1 = 5.0; /* External current [mV] for central element 1 */
double m_Icn2 = 30.0; /* External current [mV] for central element 2 */
double m_Icn1 = 5.0; /**< External current [mV] for central element 1. */
double m_Icn2 = 30.0; /**< External current [mV] for central element 2. */

double m_Vsyninh = -80.0; /* Synaptic reversal potential [mV] for inhibitory effects */
double m_Vsynexc = 0.0; /* Synaptic reversal potential [mV] for exciting effects */
double m_Vsyninh = -80.0; /**< Synaptic reversal potential [mV] for inhibitory effects. */
double m_Vsynexc = 0.0; /**< Synaptic reversal potential [mV] for exciting effects. */

double m_alfa_inhibitory = 6.0; /* Alfa-parameter for alfa-function for inhibitory effect */
double m_betta_inhibitory = 0.3; /* Betta-parameter for alfa-function for inhibitory effect */
double m_alfa_inhibitory = 6.0; /**< Alfa-parameter for alfa-function for inhibitory effect. */
double m_betta_inhibitory = 0.3; /**< Betta-parameter for alfa-function for inhibitory effect. */

double m_alfa_excitatory = 40.0; /* Alfa-parameter for alfa-function for excitatoty effect */
double m_betta_excitatory = 2.0; /* Betta-parameter for alfa-function for excitatoty effect */
double m_alfa_excitatory = 40.0; /**< Alfa-parameter for alfa-function for excitatoty effect. */
double m_betta_excitatory = 2.0; /**< Betta-parameter for alfa-function for excitatoty effect. */

double m_w1 = 0.1; /* Strength of the synaptic connection from PN to CN1 */
double m_w2 = 9.0; /* Strength of the synaptic connection from CN1 to PN */
double m_w3 = 5.0; /* Strength of the synaptic connection from CN2 to PN */
double m_w1 = 0.1; /**< Strength of the synaptic connection from PN to CN1. */
double m_w2 = 9.0; /**< Strength of the synaptic connection from CN1 to PN. */
double m_w3 = 5.0; /**< Strength of the synaptic connection from CN2 to PN. */

double m_deltah = 650.0; /* Period of time [ms] when high strength value of synaptic connection exists from CN2 to PN */
double m_threshold = -10; /* Threshold of the membrane potential that should exceeded by oscillator to be considered as an active */
double m_eps = 0.16; /* Affects pulse counter */
double m_deltah = 650.0; /**< Period of time [ms] when high strength value of synaptic connection exists from CN2 to PN. */
double m_threshold = -10; /**< Threshold of the membrane potential that should exceeded by oscillator to be considered as an active. */
double m_eps = 0.16; /**< Devider of pulse threshold counter `1.0 / eps`. */
};



struct basic_neuron_state {
public:
double m_membrane_potential = 0.0; /* Membrane potential of cenral neuron (V) */
double m_active_cond_sodium = 0.0; /* Activation conductance of the sodium channel (m) */
double m_inactive_cond_sodium = 0.0; /* Inactivaton conductance of the sodium channel (h) */
double m_active_cond_potassium = 0.0; /* Activaton conductance of the sodium channel (h) */
double m_membrane_potential = 0.0; /**< Membrane potential of cenral neuron (V). */
double m_active_cond_sodium = 0.0; /**< Activation conductance of the sodium channel (m). */
double m_inactive_cond_sodium = 0.0; /**< Inactivaton conductance of the sodium channel (h). */
double m_active_cond_potassium = 0.0; /**< Activaton conductance of the sodium channel (h). */

bool m_pulse_generation = false; /* Spike generation of central neuron */
std::vector<double> m_pulse_generation_time = { }; /* Timestamps of generated pulses */
bool m_pulse_generation = false; /**< Spike generation of central neuron. */
std::vector<double> m_pulse_generation_time = { }; /**< Timestamps of generated pulses. */

double m_Iext = 0.0;
double m_Iext = 0.0; /**< External current [mV] for neuron. */
};


Expand Down
6 changes: 3 additions & 3 deletions ccore/src/container/kdtree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ kdnode::ptr kdtree::find_node_by_rule(const std::vector<double> & p_point, const

while(true) {
if (*cur_node <= p_point) {
if (p_rule(cur_node)) {
req_node = cur_node;
break;
/* no need to check each node, only when it may satisfy the condition */
if (p_rule(cur_node)) { /* compare point with point in the current node */
return cur_node;
}

if (cur_node->get_right() != nullptr) {
Expand Down
Binary file added docs/img/kd_tree_balanced_lsun.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/kd_tree_balanced_two_diamonds.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/kd_tree_unbalanced_two_diamonds.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 10 additions & 6 deletions pyclustering/cluster/cure.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ def __create_queue(self):
self.__queue[i].distance = minimal_distance

# sort clusters
self.__queue.sort(key = lambda x: x.distance, reverse = False)
self.__queue.sort(key=lambda x: x.distance, reverse = False)


def __create_kdtree(self):
Expand All @@ -511,11 +511,16 @@ def __create_kdtree(self):
@return (kdtree) k-d tree that consist of representative points of CURE clusters.
"""
self.__tree = kdtree()

representatives, payloads = [], []
for current_cluster in self.__queue:
for representative_point in current_cluster.rep:
self.__tree.insert(representative_point, current_cluster)
representatives.append(representative_point)
payloads.append(current_cluster)

# initialize it using constructor to have balanced tree at the beginning to ensure the highest performance
# when we have the biggest amount of nodes in the tree.
self.__tree = kdtree(representatives, payloads)


def __cluster_distance(self, cluster1, cluster2):
Expand All @@ -532,8 +537,7 @@ def __cluster_distance(self, cluster1, cluster2):
distance = float('inf')
for i in range(0, len(cluster1.rep)):
for k in range(0, len(cluster2.rep)):
dist = euclidean_distance_square(cluster1.rep[i], cluster2.rep[k]); # Fast mode
#dist = euclidean_distance(cluster1.rep[i], cluster2.rep[k]) # Slow mode
dist = euclidean_distance_square(cluster1.rep[i], cluster2.rep[k]) # Fast mode
if dist < distance:
distance = dist

Expand Down
4 changes: 2 additions & 2 deletions pyclustering/cluster/dbscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"""


from pyclustering.container.kdtree import kdtree
from pyclustering.container.kdtree import kdtree_balanced

from pyclustering.cluster.encoder import type_encoding

Expand Down Expand Up @@ -125,7 +125,7 @@ def process(self):

else:
if self.__data_type == 'points':
self.__kdtree = kdtree(self.__pointer_data, range(len(self.__pointer_data)))
self.__kdtree = kdtree_balanced(self.__pointer_data, range(len(self.__pointer_data)))

for i in range(0, len(self.__pointer_data)):
if self.__visited[i] is False:
Expand Down
6 changes: 3 additions & 3 deletions pyclustering/cluster/optics.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
warnings.warn("Impossible to import matplotlib (please, install 'matplotlib'), pyclustering's visualization "
"functionality is not available (details: '%s')." % str(error_instance))

from pyclustering.container.kdtree import kdtree
from pyclustering.container.kdtree import kdtree_balanced

from pyclustering.cluster.encoder import type_encoding

Expand Down Expand Up @@ -485,7 +485,7 @@ def __process_by_python(self):
"""

if self.__data_type == 'points':
self.__kdtree = kdtree(self.__sample_pointer, range(len(self.__sample_pointer)))
self.__kdtree = kdtree_balanced(self.__sample_pointer, range(len(self.__sample_pointer)))

self.__allocate_clusters()

Expand Down Expand Up @@ -746,7 +746,7 @@ def __update_order_seed(self, optic_descriptor, neighbors_descriptors, order_see
else:
if reachable_distance < self.__optics_objects[index_neighbor].reachability_distance:
self.__optics_objects[index_neighbor].reachability_distance = reachable_distance
order_seed.sort(key = lambda obj: obj.reachability_distance)
order_seed.sort(key=lambda obj: obj.reachability_distance)


def __neighbor_indexes_points(self, optic_object):
Expand Down
40 changes: 22 additions & 18 deletions pyclustering/container/examples/kdtree_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,43 @@
"""


from pyclustering.container.kdtree import kdtree, kdtree_text_visualizer;
from pyclustering.container.kdtree import kdtree, kdtree_visualizer

from pyclustering.utils import read_sample;
from pyclustering.utils import read_sample

from pyclustering.samples.definitions import SIMPLE_SAMPLES;
from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES


def template_build_visualize(sample_path):
print("KD Tree for sample: '" + sample_path + "'");
sample = read_sample(sample_path);
tree_instance = kdtree(sample);
kdtree_text_visualizer(tree_instance).visualize(True);
print("KD Tree for sample: '" + sample_path + "'")
sample = read_sample(sample_path)
tree_instance = kdtree(sample)

kdtree_visualizer(tree_instance).visualize()


def kdtree_sample_simple01():
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1);
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)

def kdtree_sample_simple02():
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE2);
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE2)

def kdtree_sample_simple03():
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE3);
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE3)

def kdtree_sample_simple04():
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE4);
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE4)

def kdtree_sample_simple05():
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE4);
template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE5)

def kdtree_fcps_two_diamonds():
template_build_visualize(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS)


kdtree_sample_simple01();
kdtree_sample_simple02();
kdtree_sample_simple03();
kdtree_sample_simple04();
kdtree_sample_simple05();
kdtree_sample_simple01()
kdtree_sample_simple02()
kdtree_sample_simple03()
kdtree_sample_simple04()
kdtree_sample_simple05()
kdtree_fcps_two_diamonds()

0 comments on commit d53287b

Please sign in to comment.