#ifndef _BKB_API_h_ #define _BKB_API_h_ #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include //#include #include #include //#include using std::multimap; typedef enum {Evidence_valid, Evidence_overload,Evidence_exist} Evidence_status; enum Error_status { //Error_NoError, Error_INodeNoSNode, Error_SNodeNoINode, Error_SNodeSupportsMultipleINodes, Error_ComponentDependentOnSelf, Error_INodeCycle, Error_MutualExclusivityProblem, Error_SNodeBucketSumExceedsOne, Error_ComponentConflictInSNode }; /** BKB_API provides the interface to some basic BKB functions including input, set evidence and BKB reasoning. In order to use the API, one needs to initialize a BKB_API object first. As soon as the BKB_API object is created, an empty bkb will be constructed. Then the first thing to do is to input I-nodes and S-nodes. There are two ways to do input. The first way is to input I-nodes and S-nodes one by one by calling "newRV", "newState", and "newRelation". The second way is to load a bkb file. The second thing to do is to set evidence and marginal evidence by calling "setEvidence" and "setMarginalEvidence". The last thing is to reason the bkb. There are two ways to do reasoning, belief revision and belief updating. The details about belief revsion and belief updating can be found in the documentation of the two functions. After belief revision, one can get the assignment of each random variable by calling "getAssignment". After belief updating, one can get the probablity of each I-node by calling "getProbability". We added temporal information in BKB, which means 1. We can add temporal constraints between two I-nodes. Right now, we only allow StartsAfter relationship which defines the delay between the starting time of two I-nodes. This relationship can happen between parent and child (child I-node starts several units later than parent I-node) and between two parents of a child (parent1 of the child I-node starts several units later than parent2 of the child I-node). Temporal constraints are created during the construction of a BKB. 2. We can set temporal evidence of an I-node. It means when setting evidence, we can provide the time information of an I-node. Detail will be discussed later. 3. We can obtain the time assignment of an I-node after belief revision. Time assignment include the start time, the end time and the duration of an I-node. After doing belief revision, both the state assignment and time assignment can be obtained. If the time assignment is a time interval rather than a time point, an arbitary time point within the time interval will be chosen. Besides, we also enable the retrieval of all the probable worlds ordered by their probabilities. The first retrieved world is the best world, the second one is the second best and so on. Users can keep moving to the next best world by calling 'moveToNextAnswer()' until no world can be retrieved. About probability: 1. Conditional Probability Conditional probability is the probability of some event 'A', given the occurrence of some other event 'B'. Conditional probability is written P(A|B), and is read "the probability of A, given B". In a bkb, conditional probability is stored in S-Nodes. 2. Marginal Probability Marginal probability is the unconditional probability P(A) of the event 'A'; that is, the probability of 'A', regardless of whether event 'B' did or did not occur. 3. Joint Probability Joint probability is the probability of two events in conjunction; that is, the probability of both events together. The joint probability of 'A' and 'B' is written P(A, B). Any joint probability can be factored into the product of a marginal probability and a conditional probability: P(A, B) = P(B) * P(A|B). Let 'r' be an inference of a BKB. Then the probability(or the weight) of 'r' is the joint probability of the r.v. instantiations contained in the I-Nodes of 'r'. About set evidence: 1. setEvidence One can use "setEvidence" to set an I-Node to evidence before reasoning. For example, I know that 'A' is absolutely 'True'. Then I can set the I-Node 'A/True' as evidence. It is the same as setting the marginal probability of 'A=True" to 1. 2. setMarginalEvidence "setMarginalEvidence" is used to set the marginal probability of an I-Node. For example, I know that the probability of 'A' being 'True' is 0.5 irrespective of the values of the others. Then I can set the marginal probability of 'A=True' to 0.5. 3. setTemporalEvidence "setTemporalEvidence" is used to set the time information of an I-Node. For example, I know that 'A' being 'True' will only start from 1000. Then I can set the start time of 'A=True' to 1000. */ class BKB_API { diGraph kb; doublyLinkedList components; //multimap node_list; //pair node_list; multimap node_list; //class BKB_gateway* gw; enum BKB_requestCode request_code; long request_id; //char name[256]; //BKB_gateway *gw; bayesianKnowledgeBase *bkb; //char answer[256]; long next_evi; long next_mevi; long next_tevi; long num_evidence; // long num_tmp_evidence; long num_marg_evidence; long num_temp_evidence; BKBR_evidence* evidence; //= NULL; // BKBR_evidence* tmp_evidence; //= NULL; BKBR_marginalEvidence* marg_evidence;// = NULL; BKBR_temporalEvidence* temp_evidence;// = NULL; BKBR_beliefRevision* doRevision;// = new BKBR_beliefRevision BKBR_revision* revision;// = NULL; // BKBR_beliefRevision* tmp_doRevision;// = new BKBR_beliefRevision // BKBR_revision* tmp_revision;// = NULL; bool doBeliefPrediction; bool predicted; BKBR_update* update;// = NULL; //long diag_level; //long state_index; //long i; //long j; //long k; //long l; long select_rv; long select_inode; long sel_rv; long sel_inode; long sel_snode; BKB_handle rv_handle; BKB_handle inode_handle; BKB_handle rv_handle2; BKB_handle inode_handle2; BKB_handle rv_handle3; BKB_handle inode_handle3; BKB_handle snode_handle; long num_snodes; long current_answer; /* long* prv_idx; long* prv_statenum; long* prv_curstate; long total; MATH_PACK bestProbability; int size; */ //bool checkConsistency; //multimap node_list; //multimap node_list; //char* s = NULL; //char* t = NULL; public: // Constructor / Destructor /** Constructor of BKB_API. Number of evidence and number of marginal evidence are initialized to zeros. */ BKB_API(); /** Constructor of BKB_API. @param n_evi number of evidence to be set. If there is no evidence, input 0 as n_evi. @param n_mevi number of marginal evidence to be set. If there is no marginal evidence, input 0 as n_mevi. */ BKB_API(long n_evi, long n_mevi, long n_tevi); /** Destructor of BKB_API. */ ~BKB_API(); /*BKB_handle addArc(BKB_handle source_node_handle, BKB_handle sink_node_handle); BKB_handle newSNode(class BKB_S_node* snode_info); BKB_handle getComponentINode(BKB_handle component_handle, char* state); BKB_handle getComponentHandle(char* name); BKB_handle newComponent(char* name); // Returns 0 if component already exists. BKB_handle newState(BKB_handle component_handle, char* state);*/ /** Save the constructed bkb into a .bkb file. @param filename name of the .bkb file */ void saveBKB(char* filename); /** Create a random variable. Note that a random variable may have more than one states therefore more than one I-Nodes. @param rvname random variable name @return handle of the random variable */ BKB_handle newRV(char* rvname); /** Rename a random variable. @param rvname original random variable name @param newname new random variable name @return true if successful, false otherwise */ bool renameRV(char* rvname, char* newname); /** Create a state to a random variable e.g. newState('A', 'Yes') would create the state "Yes" of the random variable "A" @param rvname name of the random variable to which a state will be added @param statename name of the state to be added @return handle of the i-node with name 'rvname' and state 'statename' */ BKB_handle newState(char* rvname, char* statename); /** Rename a state of a random variable e.g. renameState('A', 'Yes', 'Maybe') would rename the I-Node "A=Yes" to "A=Maybe" @param rvname name of the random variable whose state will be renamed @param statename orignal state name @param newstate new state name @return true if successful, false otherwise */ bool renameState(char* rvname, char* statename, char* newstate); /** Delete an I-Node, its incoming arcs with corresponding S-Node and its outgoing arcs. random variable of the I-Node to be deleted @param statename state of the I-Node to be deleted */ void deleteINode(char* rvname, char* statename); /** Create a relation by constructing an S-Node and using it to link two I-Nodes. Note that an S-Node can have 0 or multiple parents but exactly 1 child. The element in "prname" and the element in "prstate" with the same index are in a pair. For example, prstate[0] is a state of the r.v. prname[0], and the I-Node named by prname[0] with state prstate[0] is a parent of the S-Node. If the S-Node has 0 parent I-Node, put 0 in "prname" and "prstate". @param prname array of names of parents of the S-Node @param prstate array of states of parents of the S-Node @param chname name of the chile I-Node of the S-Node @param chstate state of the chile I-Node of the S-Node @param prob probability of the S-Node @return handle of the S-Node */ BKB_handle newRelation(long pr_num, char** prname, char** prstate, char* chname, char* chstate, double prob); //void resetProbability(long pr_num, char** prname, char** prstate, char* chname, char* chstate, double prob); /** Reset the probability of an S-Node. e.g. resetProbability(snode_between_A=True_B=True, 0.1) where snode_between_A=True_B=True denotes the handle of the S-Node between A=True and B=True would set the S-Node's probability to 0.1 @param snode_handle handle of the S-Node whose probability is to be reset @param prob new probability */ void resetProbability(BKB_handle snode_handle, double prob); /** Delete an S-Node and all its incoming and outgoing arcs. @param snode_handle handle of the S-Node to be deleted */ void deleteRelation(BKB_handle snode_handle); /** Get the state name of an I-Node. @param inode_handle handle of the I-Node whose state is to be retrieved @return state name of the I-Node */ char* getINodeState(BKB_handle inode_handle){return bkb->getINodeState(inode_handle);} /** Get the random variable name of an I-Node. @param inode_handle handle of the I-Node whose random variable is to be retrieved @return random variable name of the I-Node */ char* getINodeName(BKB_handle inode_handle); long getComponentNumber(); char* getComponentName(BKB_handle handle); /** Get the handle of an I-Node given its random variable and state @param rvname random variable of the I-Node whose handle is to be retrieved @param statename state of the I-Node whose handle is to be retrieved @return handle of the I-Node */ BKB_handle getINodeHandle(char* rvname, char* statename); /** Get the probability of an S-Node @param snode_handle handle of the S-Node whose probability is to be retrieved @return probability of the S-Node */ MATH_PACK getSNodeProbability(BKB_handle snode_handle){return bkb->getSNodeProbability(snode_handle);}; /** Get the type of a node. The types include _I_node and _S_node. @param node_handle handle of the node whose type is to be retrieved @return type of the node */ BKB_nodeType getNodeType(BKB_handle node_handle){return bkb->getNodeType(node_handle);} /** Create temporal constraint between two nodes. The constraint can be described as INode1 starts "time" units earlier than INode2 does. e.g. If "A=True" must start 100 units earlier than "B=True", and this temporal constraint is only applied on the S-node between them, then we can use setINode1StartsAfterINode2Starts(1, snode_between_A=True_B=True, B=True, A=True, 100) to define the constraint. Note that the second parameter is an array of handles of the s-nodes to which the temporal constraint will be applied on. The third and the fourth parameters are i-node handles. The handles can be obtained when creating the nodes. @param num_snode number of s-nodes to which the temporal constraint are applied on @param snode_handle array of handles of s-nodes which connect INode1 and INode2 @param inode1_handle handle of INode1. Note that INode1 starts later than INode2. @param inode2_handle handle of INode2. Note that INode2 starts earlier than INode2. @param time time units to be delayed @return If successful return true, else return false. */ bool setINode1StartsAfterINode2Starts(long num_snode, BKB_handle* snode_handle, BKB_handle inode1_handle, BKB_handle inode2_handle, MATH_PACK time); /** Create temporal constraint between two nodes. The constraint can be described as INode1 starts "time" units earlier than INode2 does. The temporal constraint will be applied on all s-nodes connecting the two i-nodes. e.g. If "A=True" must start 100 units earlier than "B=True" under all circumstances, then we can use setINode1StartsAfterINode2Starts(B=True, A=True, 100) to define the constraint. Note that the first two parameters are i-node handles. The handles can be obtained when creating the nodes. @param inode1_handle handle of INode1. Note that INode1 starts later than INode2. @param inode2_handle handle of INode2. Note that INode2 starts earlier than INode2. @param time time units to be delayed @return If successful return true, else return false. */ bool setINode1StartsAfterINode2Starts(BKB_handle inode1_handle, BKB_handle inode2_handle, MATH_PACK time); /** Create a temporal constraint between two nodes. The constaint can be described as INode1 starts "time" units earlier than INode2 does. The temporal constraint will be applied on all s-nodes connecting the two i-nodes. e.g. setINode1StartsAfterINode2Starts(1, 1, 0, 0, 500) would require the INode with name index 1 and state index 1 to start 500 units later than the INode with name index 0 and state index 0 in whichever way they are connected. @param rv1_idx name index of INode1. Note that INode1 starts later than INode2. @param state1_idx state index of INode1. @param rv2_idx name index of INode2. Note that INode2 starts earlier than INode1. @param state2_idx state index of INode2. @param time time units to be delayed @return If successful return true, else return false. */ bool setINode1StartsAfterINode2Starts(long rv1_idx, long state1_idx, long rv2_idx, long state2_idx, MATH_PACK time); /** Create a temporal constraint between two nodes. The constaint can be described as INode1 starts "time" units earlier than INode2 does. The temporal constraint will be applied on all s-nodes connecting the two i-nodes. e.g. setINode1StartsAfterINode2Starts("B", "False", "A", "True", 500) would require the INode "B=False" to start 500 units later than the INode "A=True" in whichever way they are connected. @param rv1_str name of INode1. Note that INode1 starts later than INode2. @param state1_str state of INode1. @param rv2_str name of INode2. Note that INode2 starts earlier than INode1. @param state2_str state of INode2. @param time time units to be delayed @return If successful return true, else return false. */ bool setINode1StartsAfterINode2Starts(char* rv1_str, char* state1_str, char* rv2_str, char* state2_str, MATH_PACK time); /** Load a BKB file with extension .bkb @param filename file name of the bkb file */ void loadBKB(char* filename); /** Clear all existing evidence and reset the number of evidence, number of marginal evidence and number of temporal evidence. @param n_evi number of evidence to be set @param n_mevi number of marginal evidence to be set @param n_tevi number of temporal evidence to be set */ void resetEvidence(long n_evi, long n_mevi, long n_tevi); /** Set the temporal information of an I-Node. Temporal information includes the start time, end time and duration. If any of them is unknown, set the parameter to -1. The name of the I-Node is located by the r.v.'s index. The state of the I-Node is located by the state's index. e.g. setTemporalEvidence(0, 1, 100, 500, -1) would set the temporal information of the I-Node with name index 0 and state index 1. Its start time is 100, end time is 500, and the duration is unknown. @param rv_idx index of random variable @param state_idx index of state @param start start time of the i-node @param end end time of the i-node @param duration duration of the i-node */ Evidence_status setTemporalEvidence(long rv_idx, long state_idx, long start, long end, long duration); /** Set the temporal information of an I-Node. Temporal information includes the start time, end time and duration. If any of them is unknown, set the parameter to -1. The name of the I-Node is located by the r.v.'s name. The state of the I-Node is located by the state's name. e.g. setTemporalEvidence("A", "True", 100, 500, -1) would set the temporal information of the I-Node "A=True". Its start time is 100, end time is 500, and the duration is unknown. @param rv_str name of random variable @param state_str name of state @param start start time of the i-node @param end end time of the i-node @param duration duration of the i-node */ Evidence_status setTemporalEvidence(char* rv_str, char* state_str, long start, long end, long duration); /** Set an I-Node as evidence. The name of the I-Node is located by the r.v.'s index. The state of the I-Node is located by the state's index. e.g. setEvidence(0, 1) would set the I-Node with name index 0 and state index 1 as evidence. @param rv_idx index of random variable @param state_idx index of state */ Evidence_status setEvidence(long rv_idx, long state_idx); /** Set an I-Node as evidence. The name of the I-Node is located by the r.v.'s index. The state of the I-Node is located by the state's name. e.g. setEvidence(0, 1) would set the I-Node with name index 0 and state "Yes" as evidence. @param rv_idx index of random variable @param state_str name of state */ Evidence_status setEvidence(long rv_idx, char* state_str); /** Set an I-Node as evidence. The name of the I-Node is located by the r.v.'s name. The state of the I-Node is located by the state's name. e.g. setEvidence('A', 'Yes') would set the I-Node named by "A" with state "Yes" as evidence. @param rv_str name of random variable @param state_str name of state */ Evidence_status setEvidence(char* rv_str, char* state_str); /** Set an I-Node as evidence. The name of the I-Node is located by the r.v.'s name. The state of the I-Node is located by the state's index. e.g. setEvidence('A', 'Yes') would set the I-Node named by "A" with state index 1 as evidence. @param rv_str name of random variable @param state_idx index of state */ Evidence_status setEvidence(char* rv_str, long state_idx); /** Set a marginal evidence in the bkb The name of the I-Node is located by the r.v.'s index. The state of the I-Node is located by the state's index. @param rv_idx index of random variable @param state_idx index of state @param prob marginal probability of the state of the random variable */ Evidence_status setMarginalEvidence(long rv_idx, long state_idx, double prob); /** Set a marginal evidence in the bkb The name of the I-Node is located by the r.v.'s index. The state of the I-Node is located by the state's name. @param rv_idx index of random variable @param state_str name of state @param prob marginal probability of the state of the random variable */ Evidence_status setMarginalEvidence(long rv_idx, char* state_str, double prob); /** Set a marginal evidence in the bkb The name of the I-Node is located by the r.v.'s name. The state of the I-Node is located by the state's name. @param rv_str name of random variable @param state_str name of state @param prob marginal probability of the state of the random variable */ Evidence_status setMarginalEvidence(char* rv_str, char* state_str, double prob); /** Set a marginal evidence in the bkb The name of the I-Node is located by the r.v.'s name. The state of the I-Node is located by the state's index. @param rv_str name of random variable @param state_idx index of state @param prob marginal probability of the state of the random variable */ Evidence_status setMarginalEvidence(char* rv_str, long state_idx, double prob); /** Do belief revision. Belief revision determines the overal state of the world represented by a single complete joint instantiation to all r.v.s. There are two kind of questions that can be solved by belief revision. 1. Given evidence 'e', what is the most probable state of the world. 2. Given evidence 'e', we are interested in the state of r.v. 'A'. What is the most likely state of the world for an instantiation 'a' of 'A' that is consistent with 'e'? About reasoning result: The result of belief revision is the state assignment of each random variable that is relevent to the evidence, which can be obtained by "getAssignment(long rv_idx)" or "getAssignment(char* rv_str)". */ void beliefRevision(); BKB_handle* getComponentsHandle(); /** Move to the next most probable world. After calling moveToNextAnswer(), assignments of all the variables will change to the next most probable states. If successful, it will return true. If no more answer can be retrieved, it will return false. @return If successful return true, else return false. */ bool moveToNextAnswer(); //bool moveToAnswer(long ans_idx); /** Get assignment of a random variable after belief revision. The random variable is located by its index. e.g. getAssignment(0) would return the state assignment of random variable with index 0. @param rv_idx index of random variable @return return state assignment */ char* getAssignment(long rv_idx); /** Get assignment of a random variable after belief revision. The random variable is located by its index. e.g. getAssignment(0) would return the state assignment of random variable with index 0. @param rv_idx index of random variable @return return state assignment */ // char* getAssignment(long rv_idx, long time); /** Get assignment of a random variable after belief revision. The random variable is located by its name. e.g. getAssignment('A') would return the state assignment of random variable "A". @param rv_str name of random variable @return return state assignment */ char* getAssignment(char* rv_str); /** Get the start time of a random variable after belief revision. The random variable is located by its index. e.g. getStartTime(0) would return the assigned start time of random variable with index 0. @param rv_idx index of random variable @return return start time */ MATH_PACK getStartTime(long rv_idx); /** Get the start time of a random variable after belief revision. The random variable is located by its name. e.g. getStartTime("A") would return the assigned start time of random variable "A". @param rv_str name of random variable @return return start time */ MATH_PACK getStartTime(char* rv_str); /** Get the end time of a random variable after belief revision. The random variable is located by its index. e.g. getEndTime(0) would return the assigned end time of random variable with index 0. @param rv_idx index of random variable @return return end time */ MATH_PACK getEndTime(long rv_idx); /** Get the end time of a random variable after belief revision. The random variable is located by its name. e.g. getEndTime("A") would return the assigned end time of random variable "A". @param rv_str name of random variable @return return end time */ MATH_PACK getEndTime(char* rv_str); /** Do belief updating. Belief updating computes the marginal probabilities of each I-Node. About reasoning result: The result of belief updating is the probability of each random variable being in each of its states, which can be obtained by "getProbability(long rv_idx, long state_idx)" or "getProbability(char* rv_str, char* state_str)". */ void beliefUpdate(); /** Get probability of an I-Node after belief updating. The I-node is located by its r.v.'s index and its state's index. e.g. getProbability(0, 1) would return the probability of the I-Node with name index 0 and state index 1. @param rv_idx index of random variable @param state_idx index of state of the random variable @return return probability */ MATH_PACK getProbability(long rv_idx, long state_idx); /** Get probability of an I-Node after belief updating. The I-node is located by its r.v.'s name and its state's name. e.g. getProbability('A', 'Yes') would return the probability of the I-Node named by "A" with state "Yes". @param rv_str name of random variable @param state_str name of state of the random variable @return return probability */ MATH_PACK getProbability(char* rv_str, char* state_str); /** Get the joint probability of the current world after belief revision. @return probability of the current world */ MATH_PACK getWorldProbability(); //long getNumberINodes(){return bkb->getNumberINodes();} /** Turn on consistency check so that consistency problem will be automatically checked whenever the bkb is modified. */ void consistencyCheckOn(){bkb->consistencyCheckOn();} /** Turn off consistency check so that consistency problem will NOT be checked. */ void consistencyCheckOff(){bkb->consistencyCheckOff();} // void beliefPredictionOn(){doBeliefPrediction=true;} // void beliefPredictionOff(){doBeliefPrediction=false;} /** Get the error list that contains all the consistency errors. The error list is in the form of a multimap, in which each error is stored in the form of a pair. Note that a single node may have more than one error in the list. If there is no error in the entire bkb, the returned list is empty.For more detailed operations of multimap, please refer to STL reference. @return error list containing all consistency errors in the bkb */ multimap getErrorList(); /** Get the error statuses of a node given its handle. Error_status include 1. Error_INodeNoSNode, 2. Error_SNodeNoINode, 3. Error_SNodeSupportsMultipleINodes, 4. Error_ComponentDependentOnSelf, 5. Error_INodeCycle, 6. Error_MutualExclusivityProblem, 7. Error_SNodeBucketSumExceedsOne, 8. Error_ComponentConflictInSNode The error statuses are contained in the vector object returned. If there is no error for the node, the returned vector is empty. For more detailed operations of vector, please refer to STL reference. @param node_handle handle of the node whose error statuses are to be retrieved @return vector containing error statuses of the node */ vector getErrorStatus(BKB_handle node_handle); /** Get the error statuses of an I-Node given its random varible index and state index. The error statuses are contained in the vector object returned. If there is no error for the node, the returned vector is empty. For more detailed operations of vector, please refer to STL reference. @param rv_idx random variable index of the I-Node whose error statuses are to be retrieved @param state_idx state index of the I-Node whose error statuses are to be retrieved @return vector containing error statuses of the node */ vector getINodeErrorStatus(long rv_idx, long state_idx); /** Print out the error message on the console given its error status. @param error error status of the error to be printed */ void printErrorMessage(Error_status error); void printErrorMessage(Evidence_status status); //Error_status[] getErrorMessage(); private: void doConsistencyCheck(); void checkEviConsistency(); bool checkEviRedundancy(BKB_handle rv_handle); // void beliefPrediction(); }; #endif