Skip to content

Commit e5c018c

Browse files
committed
Merge branch 'main' into doc
2 parents 4658d40 + d95d403 commit e5c018c

8 files changed

Lines changed: 1277 additions & 369 deletions

File tree

doc/Doxyfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ FILE_PATTERNS =
769769
# be searched for input files as well.
770770
# The default value is: NO.
771771

772-
RECURSIVE = NO
772+
RECURSIVE = YES
773773

774774
# The EXCLUDE tag can be used to specify files and/or directories that should be
775775
# excluded from the INPUT source files. This way you can easily exclude a

doc/examples/clustering.ipynb

Lines changed: 1137 additions & 296 deletions
Large diffs are not rendered by default.

src/wrapper/export_distance_matrix.cpp

Lines changed: 100 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -100,88 +100,94 @@ class DistanceMatrixWrap
100100
ostringstream os;
101101

102102
int nb_cluster = len(clusters);
103-
int* cluster_nb_pattern;
104-
int** cluster_pattern;
103+
int* cluster_nb_pattern = NULL;
104+
int** cluster_pattern = NULL;
105105

106106
boost::python::list l;
107107

108108
cluster_nb_pattern = new int[nb_cluster];
109109
cluster_pattern = new int*[nb_cluster];
110110

111-
// Build dynamic 2D array
112-
try
113-
{
114-
for (int i = 0; i < nb_cluster; i++)
115-
{
116-
#ifdef DEBUG
117-
cout << "Processing cluster " << i << endl;
118-
#endif
119-
extract<boost::python::list> x(clusters[i]);
120-
121-
if (x.check()) {
122-
l = x;
123-
int nb_item = len(l);
124-
125-
cluster_nb_pattern[i] = nb_item;
126-
127-
cluster_pattern[i] = new int[nb_item];
128-
129-
for (int j = 0; j < cluster_nb_pattern[i]; j++)
130-
{
131-
cluster_pattern[i][j] = extract<int> ((l)[j]);
132-
}
133-
} else {
134-
status = false;
111+
if (nb_cluster > 1) {
112+
// Build dynamic 2D array
113+
try
114+
{
115+
for (int i = 0; i < nb_cluster; i++)
116+
{
117+
#ifdef DEBUG
118+
cout << "Processing cluster " << i << endl;
119+
#endif
120+
extract<boost::python::list> x(clusters[i]);
121+
122+
if (x.check()) {
123+
l = x;
124+
int nb_item = len(l);
125+
126+
cluster_nb_pattern[i] = nb_item;
127+
128+
cluster_pattern[i] = new int[nb_item];
129+
130+
for (int j = 0; j < cluster_nb_pattern[i]; j++)
131+
{
132+
cluster_pattern[i][j] = extract<int> ((l)[j]);
133+
}
134+
} else {
135+
status = false;
136+
}
135137
}
136138
}
137-
}
138-
catch (...)
139-
{
139+
catch (...)
140+
{
141+
// Free memory
142+
for (int i = 0; i < nb_cluster; i++)
143+
delete[] cluster_pattern[i];
144+
145+
delete[] cluster_nb_pattern;
146+
delete[] cluster_pattern;
147+
}
148+
149+
if (status) {
150+
ret = dm.partitioning(error, &os, nb_cluster, cluster_nb_pattern,
151+
cluster_pattern);
152+
140153
// Free memory
141154
for (int i = 0; i < nb_cluster; i++)
142155
delete[] cluster_pattern[i];
143156

144157
delete[] cluster_nb_pattern;
145158
delete[] cluster_pattern;
146-
}
147-
148-
if (status) {
149-
ret = dm.partitioning(error, &os, nb_cluster, cluster_nb_pattern,
150-
cluster_pattern);
159+
}} else {
160+
ret = dm.partitioning(error, &os, nb_cluster, cluster_nb_pattern,
161+
cluster_pattern);
162+
delete[] cluster_nb_pattern;
163+
delete[] cluster_pattern;
164+
}
151165

152-
// Free memory
153-
for (int i = 0; i < nb_cluster; i++)
154-
delete[] cluster_pattern[i];
166+
if (!ret)
167+
stat_tool::wrap_util::throw_error(error);
155168

156-
delete[] cluster_nb_pattern;
157-
delete[] cluster_pattern;
169+
return ret;
158170
}
159171

160-
if (!ret)
161-
stat_tool::wrap_util::throw_error(error);
172+
static std::string
173+
hierarchical_clustering(const DistanceMatrix& dm, int ialgorithm,
174+
int icriterion, const std::string path, int iformat)
175+
{
176+
StatError error;
177+
ostringstream os;
178+
hierarchical_strategy algorithm = hierarchical_strategy(ialgorithm);
179+
linkage criterion = linkage(icriterion);
180+
output_format format = output_format(iformat);
162181

163-
return ret;
164-
}
182+
bool ret;
165183

166-
static std::string
167-
hierarchical_clustering(const DistanceMatrix& dm, int ialgorithm,
168-
int icriterion, const std::string path, int iformat)
169-
{
170-
StatError error;
171-
ostringstream os;
172-
hierarchical_strategy algorithm = hierarchical_strategy(ialgorithm);
173-
linkage criterion = linkage(icriterion);
174-
output_format format = output_format(iformat);
175-
176-
bool ret;
177-
178-
ret = dm.hierarchical_clustering(error, &os, algorithm, criterion,
179-
path, format);
184+
ret = dm.hierarchical_clustering(error, &os, algorithm, criterion,
185+
path, format);
180186

181-
if (!ret)
182-
stat_tool::wrap_util::throw_error(error);
187+
if (!ret)
188+
stat_tool::wrap_util::throw_error(error);
183189

184-
return string(os.str());
190+
return string(os.str());
185191

186192
}
187193

@@ -533,7 +539,6 @@ class DistanceMatrixWrap
533539
}
534540

535541

536-
537542
};
538543

539544
#define WRAP DistanceMatrixWrap
@@ -615,6 +620,31 @@ class_distance_matrix()
615620
#undef WRAP
616621
#undef CLASS
617622

623+
class ClustersWrap
624+
{
625+
626+
public:
627+
628+
static int
629+
// Return cluster of an (individual ="pattern")
630+
// Indices are between 1 and nb_pattern for individuals
631+
// between 1 and nb_cluster for clusters
632+
get_assignment(const Clusters &cluster, int pattern)
633+
{
634+
StatError error;
635+
636+
if ((0 < pattern) & (pattern <= cluster.get_nb_pattern()))
637+
return cluster.get_assignment(pattern-1)+1;
638+
else {
639+
error.update(STAT_error[STATR_SAMPLE_INDEX]);
640+
stat_tool::wrap_util::throw_error(error);
641+
}
642+
}
643+
};
644+
645+
#define WRAP ClustersWrap
646+
#define CLASS Clusters
647+
618648
void
619649
class_cluster()
620650
{
@@ -623,8 +653,11 @@ class_cluster()
623653

624654
.def(self_ns::str(self)) // __str__
625655

626-
;
656+
.def("get_nb_cluster", &CLASS::get_nb_cluster, "Return number of clusters")
657+
.def("get_assignment", WRAP::get_assignment,
658+
args("pattern"),"Get cluster of a vector (index between 0 and nb_pattern)")
627659

660+
;
628661
/*
629662
Clusters();
630663
Clusters(const DistanceMatrix &dist_matrix , int inb_cluster ,
@@ -659,8 +692,13 @@ class_cluster()
659692
int get_pattern_length(int pattern , int cluster) const
660693
{ return pattern_length[pattern][cluster]; }
661694
*/
695+
662696
}
663697

698+
699+
#undef WRAP
700+
#undef CLASS
701+
664702
void
665703
class_dendrogram()
666704
{

test/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ test_distribution.py DONE
1818
test_error.py DONE
1919
test_estimate.py DONE
2020
test_histogram.py DONE
21-
test_matrix.py TOBECLEANED/FINALISED
21+
test_matrix.py DONE
2222
test_mixture_functional.py DONE
2323
test_mixture.py DONE
2424
test_multivariate_mixture_functional.py DONE

test/cpp/test_matrix.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ int main(void) {
5757
delete [] cluster_pattern[1];
5858
if (error.get_nb_error() > 0)
5959
cout << error;
60+
delete [] cluster_pattern;
61+
delete [] cluster_nb_pattern;
62+
cluster_pattern = new int*[1];
63+
cluster_pattern[0] = new int[1];
64+
cluster_pattern[0][0] = 0;
65+
cluster_nb_pattern = new int[1];
66+
cluster_nb_pattern[0] = 0;
67+
clust = matrix10->partitioning(error, &cout, 1, cluster_nb_pattern,
68+
cluster_pattern);
69+
delete [] cluster_pattern[0];
6070
} else {
6171
cout << error;
6272
}

test/test_cluster.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,7 @@ def test_clustering():
152152
assert str(c1) == str(matrix10.partitioning_prototype(3, [1, 3, 12], 1, 1))
153153
assert str(c1_bis) == str(matrix10.partitioning_prototype(3, [1, 3, 12], 1, 2))
154154

155+
c5 = Clustering(matrix10, "Partition", 2)
156+
assert c5
157+
assert c5.get_nb_cluster() == 2
158+
c5.get_assignment(2) == 1

test/test_distance_matrix.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
@pytest.fixture
2121
def data():
22+
# Inspired from stat_toot_test.aml
2223
vec10 = Vectors(get_shared_data("chene_sessile.vec"))
2324
vec15 = SelectVariable(vec10, [1, 3, 6], Mode="Reject")
2425
matrix10 = Compare(vec15, VectorDistance("N", "N", "N"))

test/test_matrix.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from openalea.stat_tool.comparison import Compare
1313
from openalea.stat_tool.data_transform import SelectVariable
1414
from openalea.stat_tool.vectors import VectorDistance, Vectors
15+
from openalea.stat_tool.cluster import Clustering
1516

1617
from pathlib import Path
1718

@@ -71,7 +72,6 @@ def test_get_substitution_distance(data):
7172
def test_get_insertion_distance(data):
7273
assert data.get_insertion_distance(0,0) == -1
7374

74-
# TODO: test_hierarchical_clustering
7575
def test_get_shape(data):
7676
assert (data.nb_column, data.nb_row) == (138, 138)
7777

@@ -95,22 +95,35 @@ def test_select_individual(myi):
9595
def test_select_individual(myi):
9696
assert myi.data.select_individual([1], False)
9797

98-
# def test_wrong_partitioning_clusters(myi):
99-
# assert myi.data.partitioning_clusters([0])
98+
def test_wrong_partitioning_clusters(myi):
99+
try:
100+
myi.data.partitioning_clusters([0])
101+
myi.data.partitioning_clusters([])
102+
myi.data.partitioning_clusters([[1,2], [3,4]])
103+
assert False
104+
except:
105+
assert True
100106

101107
def test_partitioning_clusters(myi):
102-
assert myi.data.partitioning_clusters([[1, 2], [3, 4]])
103-
104-
def test_partitioning_prototype(myi):
105-
# TODO: find a test that would make more sense
108+
clust1 = Clustering(myi.data, "Partition", 2)
109+
nb_clusters = clust1.get_nb_cluster()
110+
# partition
111+
part1 = [[i for i in range(1,myi.data.nb_row+1) if clust1.get_assignment(i) == c] for c in range(1,nb_clusters+1)]
112+
assert myi.data.partitioning_clusters(part1)
113+
114+
def test_wrong_partitioning_prototype(myi):
115+
"""
116+
Testing errors in partitioning_prototype.
117+
Other features of partitioning_prototype are tested in test_cluster.py
118+
"""
106119
try:
107120
assert myi.data.partitioning_prototype(0, [0], 0, 0)
108121
assert False
109122
except:
110123
assert True
111124

112125

113-
def test_symmetrize(myi):
126+
def test_wrong_symmetrize(myi):
114127
try:
115128
myi.data.symmetrize()
116129
assert False
@@ -150,4 +163,5 @@ def data():
150163

151164
test_get_column_identifier(data())
152165
test_select_individual(myi)
153-
test_partitioning_clusters(myi)
166+
test_partitioning_clusters(myi)
167+
test_wrong_partitioning_clusters(myi)

0 commit comments

Comments
 (0)