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

Revision 509, 10.9 KB (checked in by trnewman, 14 years ago)

Took out some debug and added some stats

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] + " FLOAT";
135
136        /* If this column is not the last entry, add a comma to the command in
137         * preperation for the next entry. */
138        if(i != numColumns - 1)
139            command += ", ";
140    }
141    command += ");";
142
143    /* Execute the generated command. At this point, the database is ready for
144     * use. */
145    ExecuteCommand();
146}
147
148
149CBR::CBR(string _filename, string _tablename, string _cols[], \
150        string _primcols[], uint32_t _len, uint32_t _primlen)
151{
152    /* Store database properties. */
153    filename = _filename;
154    tablename = _tablename;
155    numColumns = _len;
156
157    /* Create the database (or open it if it already exists). */
158    OpenDatabase();
159
160    /* Generate the command that will create the initial table within the
161     * VTCROSS database with primary keys. */
162    command = "CREATE TABLE " + tablename + "(";
163    for(size_t i = 0; i < numColumns; i++) {
164        command += _cols[i] + " FLOAT, ";
165    }
166
167    command += "PRIMARY KEY (";
168    for(size_t j = 0; j < _primlen; j++) {
169        command += _primcols[j];
170
171        /* If this column is not the last entry, add a comma to the command in
172         * preperation for the next entry. */
173        if(j != _primlen - 1)
174            command += ", ";
175    }
176    command += "));";
177
178    /* Execute the generated command. At this point, the database is ready for
179     * use. */
180    ExecuteCommand();
181}
182
183
184CBR::~CBR()
185
186    /* Generate the sqlite command to delete a table and all of its contents,
187     * and then execute it. */
188    command = "drop table " + tablename;
189    ExecuteCommand();
190
191    /* Tell sqlite to clean up the database. */
192    command = "vacuum";
193    ExecuteCommand();
194}
195
196
197int32_t
198CBR::OpenDatabase()
199{
200    int32_t rc = sqlite3_open(filename.c_str(), &db);
201    if(rc) {
202        WARNING("Can't open database: %s\n", sqlite3_errmsg(db));
203        sqlite3_close(db);
204        exit(1);
205    }
206
207    return rc;
208}
209
210
211int32_t
212CBR::ExecuteCommand()
213{
214    char *zErrMsg = 0;
215
216    int32_t rc = sqlite3_exec(db, command.c_str(), callback, 0, &zErrMsg);
217    if(rc != SQLITE_OK) {
218        WARNING("SQL error: %s: %s\n", zErrMsg, command.c_str());
219        sqlite3_free(zErrMsg);
220    }
221
222    return rc;
223}
224
225
226int32_t
227CBR::ExecuteSearchCommand(float *_retvals)
228{
229    sqlite3_stmt *pStatement;
230
231    int32_t rc = sqlite3_prepare_v2(db, command.c_str(), -1, &pStatement, NULL);
232    if(rc == SQLITE_OK) {
233        if(sqlite3_step(pStatement) == SQLITE_ROW) {
234            for(size_t i = 0; i < numColumns; ++i) {
235                _retvals[i] = sqlite3_column_double(pStatement, i);
236            }
237        } else {
238                    LOG("CBR:: No matched results returning default.\n");
239                        rc = 31337;
240                }
241    } else {
242                WARNING("CBR:: Error executing SQL statement. rc = %i\n%s\n", rc, command.c_str());
243    }
244
245    sqlite3_finalize(pStatement);
246   
247    return rc;
248}
249
250
251void
252CBR::Print()
253{
254    /* Generate the sqlite command to print the database, which is effectively a
255     * 'select all elements' command, and then execute it. */
256    command = "select " + tablename + ".* from " + tablename + ";";
257
258    ExecuteCommand();
259    LOG("database %s, table %s:\n", filename.c_str(), tablename.c_str());
260}
261
262
263int32_t
264CBR::Search(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
265        float *_retvals)
266{   
267    char str_buffer[64];
268    const string ops_str[] = {"==", "!=", ">", ">=", "<", "<="};
269
270    command = "select " + tablename + ".* from " + tablename + " where ";
271
272    for(size_t i = 0; i < _n; i++) {
273        /* Make sure that the passed ops value is valid. */
274        if((_ops[i] < 0) || (_ops[i] > 5)) {
275            ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]);
276        }
277
278        command += _names[i] + ops_str[_ops[i]];
279
280
281        sprintf(str_buffer, "%E", _vals[i]);
282        command += string(str_buffer);
283
284        if(i < _n - 1)
285            command += " AND ";
286        else
287            command += " order by utility desc;";
288       
289    }
290    //LOG("CBR::Search - command: %s\n", command.c_str());
291
292    return ExecuteSearchCommand(_retvals);
293}
294
295
296int32_t
297CBR::SearchSum(string _name, float *_retvals)
298{   
299    command = "select SUM(" + tablename + "." + _name + ") from " + tablename + ";";
300
301    return ExecuteSearchCommand(_retvals);
302}
303
304
305int32_t
306CBR::SearchRand(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
307        float *_retvals)
308{   
309    char str_buffer[64];
310    const char *ops_str[] = {"==", "!=", ">", ">=", "<", "<="};
311
312    command = "select " + tablename + ".* from " + tablename + " where ";
313
314    for(size_t i = 0; i < _n; i++) {
315        /* Make sure that the passed ops value is valid. */
316        if((_ops[i] < 0) || (_ops[i] > 5)) {
317            ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]);
318        }
319
320        command += _names[i] + ops_str[_ops[i]];
321
322        sprintf(str_buffer, "%E", _vals[i]);
323        command += str_buffer;
324
325        if(i < _n - 1)
326            command += " AND ";
327        else
328            command += " order by RAND();";
329    }
330
331    return ExecuteSearchCommand(_retvals);
332}
333
334
335int32_t
336CBR::Update(string _where[], string _set[], float *_wherevals, float *_setvals,
337                uint32_t _wherelen, uint32_t _setlen)
338{
339    char str_buffer[64];
340
341    /* Generate the command to update the table. */
342    command = "UPDATE " + tablename + " SET ";
343
344    for(size_t i = 0; i < _setlen; i++) {
345        command += _set[i] + " = ";
346        sprintf(str_buffer, "%f", _setvals[i]);
347        command += string(str_buffer) + "  ";
348
349        if(i != _setlen - 1)
350            command += ", ";
351    }
352    command += " WHERE ";
353
354    for(size_t j = 0; j < _wherelen; j++) {
355        command += _where[j] + " = ";
356        sprintf(str_buffer, "%f", _wherevals[j]);
357        command += string(str_buffer) + "  ";
358
359        if(j != _wherelen - 1)
360            command += "AND ";
361    }
362    command += ";";
363   
364    return ExecuteCommand();
365}
366
367
368int32_t
369CBR::AddRow(string _cols[], float *_vals, uint32_t _len)
370{
371    char str_buffer[64];
372
373    command = "insert into " + tablename + " (";
374
375    for(size_t i = 0; i < _len; i++) {
376        command += _cols[i];
377
378        if(i != numColumns - 1)
379            command += ", ";
380    }
381    command += ") values(";
382
383    for(size_t j = 0; j < _len; j++) {
384        // TODO I have no idea what the below question is about.
385        // ???? how to fill the values if numColumns != _len
386        // assume = in the following
387        sprintf(str_buffer, "%f", _vals[j]);
388        command += str_buffer;
389
390        if(j != numColumns - 1)
391            command += ", ";
392    }
393    command += ");";
394   
395    return ExecuteCommand();
396}
397
398#endif
Note: See TracBrowser for help on using the browser.