The approach we've taken is to define "categories", to allow persons to be associated with categories of demographic information, and to allow items to be associated with categories of descriptive information. Here are examples of possible demographic categories:
age_0_20
age_21_35
age_36_54
age_55_up
job_doctor
job_lawyer
job_teacher
zip_9xxxx
And
here are examples of item description categories for a travel information
application:
restaurant_French
restaurant_Chinese
music_blues
music_classical
recreation_bicycling
Note:
We do not allow a person to explicitly rate a whole category, e.g., it is not
possible to say "I like Chinese restaurants in general." Instead, such
information is inferred. We also do not allow the specification of structural
relationships between categories, such as "Chinese restaurants are a kind of
Asian restaurant".Here are the API additions to eetypes.h:
class ee_category { // an opaque uid for a category
public:
int uid;
ee_category(int uu = 0): uid(uu) {};
};
inline int operator==(const ee_category& x, const ee_category& xx)
{ return x.uid == xx.uid; }
const ee_category ee_category_null(0); // unused "null" value
For
each category, there is a model (just as with persons and items). The schema
for nonvolatile storage needs to be extended with a Categories table
to hold the category models:
ee_category category; // unique key
ee_model model;
There must also be a mechanism (tables or procedures) to map information about persons and items to categories.
Here are the additions to eepredict.h:
(a) Add two member functions:
void reset_person_category(
const ee_person x, const ee_category c, const float w);
/* Assert c as a category for person x with weight w; remove any
such assertion if w==0. This call should follow any change in
the nonvolatile database; it resets any cache the predictor may
have kept. */
void reset_item_category(
const ee_item y, const ee_category c, const float w);
/* Assert c as a category for item y with weight w; remove any such
assertion if w is 0. This call should follow any change in the
nonvolatile database; it resets any cache the predictor may have
kept. */
(b) Add two pure virtual functions (to be implemented by the application
programmer):
virtual void get_person_categories(
const ee_person x,
void (*setcategory)(
const ee_person x, const ee_category c, const float w, void* a),
void* arg) = 0;
/* Retrieve all categories (and weights) for person x from nonvolatile
storage, calling (*setcategory)(x, category, weight, arg) for each. */
virtual void get_person_category_model(
const ee_category c,
ee_model& m) = 0;
/* Retrieve category c's model from nonvolatile storage, and return
it in m; if there is no model, return the null model. */
Finally, here are the additions to eesolve.h:
(a) Add four member functions to class ee_solve:
void set_category_model(const ee_category c, const ee_model& m);
/* Set the model for category c to be m. Before initialization, a
model is treated as null. */
void set_person_in_category(
const ee_person x, const ee_category c, const float w);
/* Assert that x is a member of c with weight w; a zero weight
clears an assertion. */
void set_item_in_category(
const ee_item y, const ee_category c, const float w);
/* Assert that y is a member of c with weight w; a zero weight
clears an assertion. */
void get_category_model(const ee_category c, ee_model& m);
/* Set m to category c's model. */
(b)
Add a new class:
class category_iterator {
public:
category_iterator(ee_solve& s); // constructor
~category_iterator(); // destructor
ee_category get_next(); // iterate over categories
private:
// Disable the copy constructor and assignment operator:
category_iterator(const category_iterator& rhs);
category_iterator& operator=(const category_iterator& rhs);
ee_solve_category_iterator_impl *impl; // instance data
};
friend class category_iterator;
/* A category_iterator is used to discover all the categories known
to the solver. A category is known to the solver if one or more
persons or items have been registered in that category via
set_person_in_category or set_item_in_category and not deleted
via restart, or if a model for that category has been registered
via set_category_model and not deleted via restart.
Each call to get_next returns another category not previously
returned since the iterator was constructed, or ee_category_null
if none remain. The result of interleaving calls to get_next
with calls to set_*_in_category or set_category_model is undefined. */