root/vtcross/trunk/src/include/vtcross/cbr.h @ 472

Revision 472, 11.0 KB (checked in by bhilburn, 15 years ago)

Cleaned up the CBR code and converted it from c-strings to std::string.
Need to propogate this change through the various CE codes.

Line 
1/*
2 Copyright 2009 Virginia Polytechnic Institute and State University 
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/* This file contains the full implementation of the CBR class - the default
18 * VTCROSS case-based reasoner.
19 */
20
21
22
23#ifndef CBR_H
24#define CBR_H
25
26#include <cstdlib>
27#include <cstring>
28#include <cstdio>
29#include <stdint.h>
30#include <string>
31
32#include <sqlite3.h>
33
34#include "vtcross/common.h"
35#include "vtcross/debug.h"
36#include "vtcross/error.h"
37
38using namespace std;
39
40
41#define DATABASENAME "vtcross_cbr"
42
43
44/* This is an internal debugging function used by some sqlite3 function calls.
45 * It is not used otherwise in the VTCROSS codebase. */
46int32_t
47callback(void *notUsed, int argc, char **argv, char **azColName)
48{
49    for(size_t i = 0; i < argc; i++) {
50        LOG("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
51    }
52    LOG("\n");
53
54    return 0;
55}
56
57
58/* The CBR class is designed to used as either as-is, or as a parent class.  All
59 * functions are declared virtual, and internal members are 'protected' rather
60 * than private. If you require functionality in a CBR not specifically provided
61 * by this class, include this header in your source file, create a new class
62 * that derives from CBR, and implement your desired functionality over the
63 * original virtual functions as necessary.
64 */
65class CBR
66{
67    public:
68        /* Constructors for the CBR class. Note that the default constructor
69         * must be defined inline here so that super-calls from child classes
70         * don't fail (i.e. we cannot rely on the compiler-provided constructor. */
71        CBR(){};
72        CBR(string _filename, string _tablename, string _cols[], uint32_t _len);
73        CBR(string _filename, string _tablename, string _cols[], \
74                string _primcols[], uint32_t _len, uint32_t _primlen);
75
76        /* Destructor for the CBR class. Note that this destructor will be
77         * called automatically by any derived classes, and so child classes
78         * should not repeat the freeing actions performed in this function. */
79        virtual ~CBR();
80
81        /* This function opens the VTCROSS database, or if it has not been
82         * created yet, creates it. */
83        virtual int32_t OpenDatabase();
84
85        /* Execute a sqlite3 command and return the sqlite3 return code. */
86        virtual int32_t ExecuteCommand();
87
88        /* Execute a sqlite3 search command and store the results in the passed
89         * retvals argument. */
90        virtual int32_t ExecuteSearchCommand(float *_retvals);
91
92        /* Print the VTCROSS sqlite3 database. */
93        virtual void Print();
94
95        /* Search the VTCROSS database for specific fields and store the results
96         * in the passed retvals argument. */
97        virtual int32_t Search(string _names[], int32_t *_ops, float *_vals, \
98                uint32_t _n, float *_retvals);
99        virtual int32_t SearchSum(string _name, float *_retvals);
100        virtual int32_t SearchRand(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
101            float *_retvals);
102
103        /* Update a row in the VTCROSS sqlite3 database. */
104        virtual int32_t Update(string _where[], string _set[], float *_wherevals, \
105                float *_setvals, uint32_t _wherelen, uint32_t _setlen);
106
107        /* Add a row to the VTCROSS sqlite3 database. */
108        virtual int32_t AddRow(string _cols[], float *_vals, uint32_t _len);
109
110    protected:
111        string filename;
112        string tablename;
113        string command;
114
115        sqlite3 *db;
116        uint32_t numColumns;
117};
118
119
120CBR::CBR(string _filename, string _tablename, string _cols[], uint32_t _len)
121{
122    /* Store database properties. */
123    filename = _filename;
124    tablename = _tablename;
125    numColumns = _len;
126
127    /* Create the database (or open it if it already exists). */
128    OpenDatabase();
129
130    /* Generate the command that will create the initial table within the
131     * VTCROSS database. */
132    command = "CREATE TABLE " + tablename + "(";
133    for(size_t i = 0; i < numColumns; i++) {
134        command += _cols[i];
135        command += " FLOAT";
136
137        /* If this column is not the last entry, add a comma to the command in
138         * preperation for the next entry. */
139        if(i != numColumns - 1)
140            command += ", ";
141    }
142    command += ");";
143
144    /* Execute the generated command. At this point, the database is ready for
145     * use. */
146    ExecuteCommand();
147}
148
149
150CBR::CBR(string _filename, string _tablename, string _cols[], \
151        string _primcols[], uint32_t _len, uint32_t _primlen)
152{
153    /* Store database properties. */
154    filename = _filename;
155    tablename = _tablename;
156    numColumns = _len;
157
158    /* Create the database (or open it if it already exists). */
159    OpenDatabase();
160
161    /* Generate the command that will create the initial table within the
162     * VTCROSS database with primary keys. */
163    command = "CREATE TABLE " + tablename + "(";
164    for(size_t i = 0; i < numColumns; i++) {
165        command += _cols[i];
166        command += " FLOAT, ";
167    }
168
169    command += "PRIMARY KEY (";
170    for(size_t j = 0; j < _primlen; j++) {
171        command += _primcols[j];
172
173        /* If this column is not the last entry, add a comma to the command in
174         * preperation for the next entry. */
175        if(j != _primlen - 1)
176            command += ", ";
177    }
178    command += "));";
179
180    /* Execute the generated command. At this point, the database is ready for
181     * use. */
182    ExecuteCommand();
183}
184
185
186CBR::~CBR()
187
188    /* Generate the sqlite command to delete a table and all of its contents,
189     * and then execute it. */
190    command = "drop table " + tablename;
191    ExecuteCommand();
192
193    /* Tell sqlite to clean up the database. */
194    command = "vacuum";
195    ExecuteCommand();
196}
197
198
199int32_t
200CBR::OpenDatabase()
201{
202    int32_t rc = sqlite3_open(filename.c_str(), &db);
203    if(rc) {
204        WARNING("Can't open database: %s\n", sqlite3_errmsg(db));
205        sqlite3_close(db);
206        exit(1);
207    }
208
209    return rc;
210}
211
212
213int32_t
214CBR::ExecuteCommand()
215{
216    char *zErrMsg = 0;
217
218    int32_t rc = sqlite3_exec(db, command.c_str(), callback, 0, &zErrMsg);
219    if(rc != SQLITE_OK) {
220        WARNING("SQL error: %s: %s\n", zErrMsg, command.c_str());
221        sqlite3_free(zErrMsg);
222    }
223
224    return rc;
225}
226
227
228int32_t
229CBR::ExecuteSearchCommand(float *_retvals)
230{
231    sqlite3_stmt *pStatement;
232
233    int32_t rc = sqlite3_prepare_v2(db, command.c_str(), -1, &pStatement, NULL);
234    if(rc == SQLITE_OK) {
235        if(sqlite3_step(pStatement) == SQLITE_ROW) {
236            for(size_t i = 0; i < numColumns; ++i) {
237                _retvals[i] = sqlite3_column_double(pStatement, i);
238            }
239        } else {
240                    LOG("CBR:: No matched results returning default.\n");
241                        rc = 31337;
242                }
243    } else {
244                WARNING("CBR:: Error executing SQL statement. rc = %i\n%s\n", rc, command.c_str());
245    }
246
247    sqlite3_finalize(pStatement);
248   
249    return rc;
250}
251
252
253void
254CBR::Print()
255{
256    /* Generate the sqlite command to print the database, which is effectively a
257     * 'select all elements' command, and then execute it. */
258    command = "select " + tablename + ".* from " + tablename + ";";
259
260    ExecuteCommand();
261    LOG("database %s, table %s:\n", filename.c_str(), tablename.c_str());
262}
263
264
265int32_t
266CBR::Search(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
267        float *_retvals)
268{   
269    LOG("CBR::Search - number of ops %d:\n", _n);
270
271    char str_buffer[64];
272    const string ops_str[] = {"==", "!=", ">", ">=", "<", "<="};
273
274    command = "select " + tablename + ".* from " + tablename + " where ";
275
276    for(size_t i = 0; i < _n; i++) {
277        /* Make sure that the passed ops value is valid. */
278        if((_ops[i] < 0) || (_ops[i] > 5)) {
279            ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]);
280        }
281
282        command += _names[i] + ops_str[_ops[i]];;
283
284        LOG("CBR::Search - command: %s\n", command.c_str());
285
286        sprintf(str_buffer, "%E", _vals[i]);
287        command += string(str_buffer);
288
289        if(i < _n - 1)
290            command += " AND ";
291        else
292            command += " order by utility desc;";
293    }
294
295    return ExecuteSearchCommand(_retvals);
296}
297
298
299int32_t
300CBR::SearchSum(string _name, float *_retvals)
301{   
302    command = "select SUM(" + tablename + "." + _name + ") from " + tablename + ";";
303
304    return ExecuteSearchCommand(_retvals);
305}
306
307
308int32_t
309CBR::SearchRand(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
310        float *_retvals)
311{   
312    char str_buffer[64];
313    const char *ops_str[] = {"==", "!=", ">", ">=", "<", "<="};
314
315    command = "select " + tablename + ".* from " + tablename + " where ";
316
317    for(size_t i = 0; i < _n; i++) {
318        /* Make sure that the passed ops value is valid. */
319        if((_ops[i] < 0) || (_ops[i] > 5)) {
320            ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]);
321        }
322
323        command += _names[i] + ops_str[_ops[i]];;
324
325        sprintf(str_buffer, "%E", _vals[i]);
326        command += str_buffer;
327
328        if(i < _n - 1)
329            command += " AND ";
330        else
331            command += " order by RAND();";
332    }
333
334    return ExecuteSearchCommand(_retvals);
335}
336
337
338int32_t
339CBR::Update(string _where[], string _set[], float *_wherevals, float *_setvals,
340                uint32_t _wherelen, uint32_t _setlen)
341{
342    char str_buffer[64];
343
344    /* Generate the command to update the table. */
345    command = "UPDATE " + tablename + " SET ";
346
347    for(size_t i = 0; i < _setlen; i++) {
348        command += _set[i] + " = ";
349        sprintf(str_buffer, "%f", _setvals[i]);
350        command += string(str_buffer) + "  ";
351
352        if(i != _setlen - 1)
353            command += ", ";
354    }
355    command += " WHERE ";
356
357    for(size_t j = 0; j < _wherelen; j++) {
358        command += _where[j] + " = ";
359        sprintf(str_buffer, "%f", _wherevals[j]);
360        command += string(str_buffer) + "  ";
361
362        if(j != _wherelen - 1)
363            command += "AND ";
364    }
365    command += ";";
366   
367    return ExecuteCommand();
368}
369
370
371int32_t
372CBR::AddRow(string _cols[], float *_vals, uint32_t _len)
373{
374    char str_buffer[64];
375
376    command = "insert into " + tablename + " (";
377
378    for(size_t i = 0; i < _len; i++) {
379        command += _cols[i];
380
381        if(i != numColumns - 1)
382            command += ", ";
383    }
384    command += ") values(";
385
386    for(size_t j = 0; j < _len; j++) {
387        // TODO I have no idea what the below question is about.
388        // ???? how to fill the values if numColumns != _len
389        // assume = in the following
390        sprintf(str_buffer, "%f", _vals[j]);
391        command += str_buffer;
392
393        if(j != numColumns - 1)
394            command += ", ";
395    }
396    command += ");";
397   
398    return ExecuteCommand();
399}
400
401#endif
Note: See TracBrowser for help on using the browser.