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_9xxxxAnd here are examples of item description categories for a travel information application:
restaurant_French restaurant_Chinese music_blues music_classical recreation_bicyclingNote: 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" valueFor 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. */