matrix.cpp 5.75 KB
Newer Older
1
2
// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
3

4
#include <dlib/python.h>
5
6
#include <boost/shared_ptr.hpp>
#include <dlib/matrix.h>
7
#include <dlib/string.h>
Davis King's avatar
Davis King committed
8
#include <boost/python/args.hpp>
9
10
11

using namespace dlib;
using namespace boost::python;
Davis King's avatar
Davis King committed
12
13
using std::string;
using std::ostringstream;
14
15
16
17
18
19
20
21


void matrix_set_size(matrix<double>& m, long nr, long nc)
{
    m.set_size(nr,nc);
    m = 0;
}

22
23
24
25
26
27
28
29
string matrix_double__repr__(matrix<double>& c)
{
    ostringstream sout;
    sout << "< dlib.matrix containing: \n";
    sout << c;
    return trim(sout.str()) + " >";
}

30
31
32
33
string matrix_double__str__(matrix<double>& c)
{
    ostringstream sout;
    sout << c;
34
    return trim(sout.str());
35
36
37
38
}

boost::shared_ptr<matrix<double> > make_matrix_from_size(long nr, long nc)
{
39
40
41
42
43
44
    if (nr < 0 || nc < 0)
    {
        PyErr_SetString( PyExc_IndexError, "Input dimensions can't be negative." 
        );                                            
        boost::python::throw_error_already_set();   
    }
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    boost::shared_ptr<matrix<double> > temp(new matrix<double>(nr,nc));
    *temp = 0;
    return temp;
}


boost::shared_ptr<matrix<double> > from_object(object obj)
{
    tuple s = extract<tuple>(obj.attr("shape"));
    if (len(s) != 2)
    {
        PyErr_SetString( PyExc_IndexError, "Input must be a matrix or some kind of 2D array." 
        );                                            
        boost::python::throw_error_already_set();   
    }

    const long nr = extract<long>(s[0]);
    const long nc = extract<long>(s[1]);
    boost::shared_ptr<matrix<double> > temp(new matrix<double>(nr,nc));
    for ( long r = 0; r < nr; ++r)
    {
        for (long c = 0; c < nc; ++c)
        {
            (*temp)(r,c) = extract<double>(obj[make_tuple(r,c)]);
        }
    }
    return temp;
}

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
boost::shared_ptr<matrix<double> > from_list(list l)
{
    const long nr = len(l);
    if (extract<list>(l[0]).check())
    {
        const long nc = len(l[0]);
        // make sure all the other rows have the same length
        for (long r = 1; r < nr; ++r)
            pyassert(len(l[r]) == nc, "All rows of a matrix must have the same number of columns.");


        boost::shared_ptr<matrix<double> > temp(new matrix<double>(nr,nc));
        for ( long r = 0; r < nr; ++r)
        {
            for (long c = 0; c < nc; ++c)
            {
                (*temp)(r,c) = extract<double>(l[r][c]);
            }
        }
        return temp;
    }
    else
    {
        // In this case we treat it like a column vector
        boost::shared_ptr<matrix<double> > temp(new matrix<double>(nr,1));
        for ( long r = 0; r < nr; ++r)
        {
            (*temp)(r) = extract<double>(l[r]);
        }
        return temp;
    }
}

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
long matrix_double__len__(matrix<double>& c)
{
    return c.nr();
}

struct mat_row
{
    mat_row() : data(0),size(0) {}
    mat_row(double* data_, long size_) : data(data_),size(size_) {}
    double* data;
    long size;
};

void mat_row__setitem__(mat_row& c, long p, double val)
{
    if (p < 0) {
        p = c.size + p; // negative index
    }
    if (p > c.size-1) {
        PyErr_SetString( PyExc_IndexError, "3 index out of range" 
        );                                            
        boost::python::throw_error_already_set();   
    }
    c.data[p] = val;
}


string mat_row__str__(mat_row& c)
{
    ostringstream sout;
    sout << mat(c.data,1, c.size);
    return sout.str();
}

141
142
143
144
145
146
147
string mat_row__repr__(mat_row& c)
{
    ostringstream sout;
    sout << "< matrix row: " << mat(c.data,1, c.size);
    return trim(sout.str()) + " >";
}

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
long mat_row__len__(mat_row& m)
{
    return m.size;
}

double mat_row__getitem__(mat_row& m, long r)
{
    if (r < 0) {
        r = m.size + r; // negative index
    }
    if (r > m.size-1 || r < 0) {
        PyErr_SetString( PyExc_IndexError, "1 index out of range" 
        );                                            
        boost::python::throw_error_already_set();   
    }
    return m.data[r];
}

mat_row matrix_double__getitem__(matrix<double>& m, long r)
{
    if (r < 0) {
        r = m.nr() + r; // negative index
    }
    if (r > m.nr()-1 || r < 0) {
        PyErr_SetString( PyExc_IndexError, (string("2 index out of range, got ") + cast_to_string(r)).c_str()
        );                                            
        boost::python::throw_error_already_set();   
    }
    return mat_row(&m(r,0),m.nc());
}


tuple get_matrix_size(matrix<double>& m)
{
    return make_tuple(m.nr(), m.nc());
}

void bind_matrix()
{
    class_<mat_row>("_row")
        .def("__len__", &mat_row__len__)
189
        .def("__repr__", &mat_row__repr__)
190
191
192
193
        .def("__str__", &mat_row__str__)
        .def("__setitem__", &mat_row__setitem__)
        .def("__getitem__", &mat_row__getitem__);

Davis King's avatar
Davis King committed
194
195
    class_<matrix<double> >("matrix", "This object represents a dense 2D matrix of floating point numbers."
        "Moreover, it binds directly to the C++ type dlib::matrix<double>.", init<>())
196
        .def("__init__", make_constructor(&make_matrix_from_size))
Davis King's avatar
Davis King committed
197
        .def("set_size", &matrix_set_size, (arg("rows"), arg("cols")), "Set the size of the matrix to the given number of rows and columns.")
198
        .def("__init__", make_constructor(&from_object))
199
        .def("__init__", make_constructor(&from_list))
200
        .def("__repr__", &matrix_double__repr__)
201
        .def("__str__", &matrix_double__str__)
Davis King's avatar
Davis King committed
202
203
        .def("nr", &matrix<double>::nr, "Return the number of rows in the matrix.")
        .def("nc", &matrix<double>::nc, "Return the number of columns in the matrix.")
204
205
206
207
208
209
        .def("__len__", &matrix_double__len__)
        .def("__getitem__", &matrix_double__getitem__, with_custodian_and_ward_postcall<0,1>())
        .add_property("shape", &get_matrix_size)
        .def_pickle(serialize_pickle<matrix<double> >());
}