/* Copyright 2009 Virginia Polytechnic Institute and State University Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #include #include #include #include "vtcross/cbr.h" #include "vtcross/cognitive_engine.h" #include "vtcross/common.h" #include "vtcross/containers.h" #include "vtcross/debug.h" #include "vtcross/error.h" #include "vtcross/socketcomm.h" static CBR *myCBR; CognitiveEngine::CognitiveEngine() { LOG("Creating Cognitive Engine.\n"); SML_present = false; commandSocketFD = -1; } CognitiveEngine::~CognitiveEngine() { delete myCBR; delete [] pList; delete [] oList; delete [] uList; delete [] radioInfo; } CognitiveEngine::CognitiveEngine(const char *serverName, const char *serverPort, \ const bool SML) { LOG("Creating Cognitive Engine.\n"); pList = new Parameter[10]; oList = new Observable[10]; uList = new Utility[10]; radioInfo = new Radio_Info; ConnectToRemoteComponent(serverName, serverPort, SML); } void CognitiveEngine::SendComponentType() { SendMessage(commandSocketFD, "response_engine_cognitive"); LOG("Cognitive Engine responded to GetRemoteComponentType query.\n"); } void CognitiveEngine::ConnectToRemoteComponent(const char *serverName, \ const char *serverPort, const bool SML) { commandSocketFD = ClientSocket(serverName, serverPort); SML_present = SML; if(SML) { RegisterComponent(); LOG("Cognitive Engine connected to SML at %s.\n", serverName); ReceiveRadioConfiguration(); ReceiveExperience(); RegisterServices(); } else { RegisterComponent(); LOG("Cognitive Engine connected to shell at %s.\n", serverName); ReceiveRadioConfiguration(); ReceiveExperience(); } } void CognitiveEngine::ReceiveFeedback(Observable *observables, Parameter *parameters) { LOG("Cognitive Engine:: Receiving feedback.\n"); uint32_t numberColumns = radioInfo->numParameters + radioInfo->numUtilities; uint32_t obsColumns = radioInfo->numObservables + 1; float valList[numberColumns]; float obsVals[numberColumns]; char *nameList[numberColumns]; char *obsList[obsColumns]; size_t columnObsIndex = 0; for (size_t i = 0; i < radioInfo->numObservables; i++){ obsList[columnObsIndex] = (char*)observables[i].name.c_str(); columnObsIndex++; } obsList[columnObsIndex] = (char *) "utility"; size_t columnIndex = 0; for (size_t i = 0; i < radioInfo->numParameters; i++){ nameList[columnIndex] = (char*)parameters[i].name.c_str(); columnIndex++; } for (size_t i = 0; i < radioInfo->numUtilities; i++){ nameList[columnIndex] = (char*)uList[i].name.c_str(); columnIndex++; } size_t obsValueIndex = 0; for(size_t i = 0; i < radioInfo->numObservables; i++) { obsVals[obsValueIndex] = observables[i].value; obsValueIndex++; } /* Calculate Utility */ float newUtilityValue = 0; for(size_t i = 0; i < radioInfo->numUtilities; i++) { newUtilityValue = newUtilityValue + (uList[i].target - observables[i].value); } obsVals[obsValueIndex] = newUtilityValue; size_t returnValueIndex = 0; for(size_t i = 0; i < radioInfo->numParameters; i++) { valList[returnValueIndex] = parameters[i].value; returnValueIndex++; } for(size_t i = 0; i < radioInfo->numUtilities; i++) { valList[returnValueIndex] = uList[i].target; returnValueIndex++; } myCBR->Update(nameList, obsList, valList, obsVals, numberColumns, obsColumns); } void CognitiveEngine::WaitForSignal() { char buffer[256]; while(true) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); // TODO this is ugly... is there a better way? Doesn't strcmp compare the // whole string? We only need to compare until we find a single different // byte... // // If we send integer op codes rather than strings, this process will be // MUCH faster since instead of donig string compares we can simply // switch on the integer value... if(strcmp(buffer, "update_performance") == 0) { /* Receive Set of current Parameters */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numParameters = atoi(buffer); Parameter *p = new Parameter[numParameters]; for(size_t i = 0; i < numParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); p[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); p[i].value = atof(buffer); } /* Receive Set of Observables */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numObservables = atoi(buffer); Observable *o = new Observable[numObservables]; for(size_t i = 0; i < numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].value = atof(buffer); } ReceiveFeedback(o,p); delete [] o; delete [] p; } else if(strcmp(buffer, "request_optimization_service") == 0) { // THIS IS CURRENTLY IN DEMO MODE /* Receive Set of Observables */ LOG("\nCognitive Engine:: Receiving service name\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); LOG("\nCognitive Engine:: Got service name, %s\n", buffer); /* Receive Set of Observables */ LOG("\nCognitive Engine:: Receiving Observable Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); uint32_t numObservables = atoi(buffer); Observable *o = new Observable[numObservables]; for(size_t i = 0; i < numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].value = atof(buffer); } /* Receive Set of current Parameters */ LOG("Cognitive Engine:: Receiving Current Transmission Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numCurrentParameters = atoi(buffer); Parameter *cp = new Parameter[numCurrentParameters]; for(size_t i = 0; i < numCurrentParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].value = atof(buffer); } LOG("Cognitive Engine:: Processing parameters....\n"); //Parameter *solutionSet; //solutionSet = GetSolution(o,cp); // TODO need to actually do something with the observables here LOG("Cognitive Engine:: Sending Optimal Parameters to Application.\n"); char numParametersChar[10]; //char solutionValue[50]; sprintf(numParametersChar, "%i", radioInfo->numParameters); SendMessage(commandSocketFD, numParametersChar); for(size_t i = 0; i < radioInfo->numParameters; i++) { //SendMessage(commandSocketFD, solutionSet[i].name.c_str()); SendMessage(commandSocketFD, "test"); //memset(solutionValue, 0, 50); //sprintf(solutionValue, "%f", solutionSet[i].value); //SendMessage(commandSocketFD, solutionValue); SendMessage(commandSocketFD, "00"); } delete [] o; delete [] cp; } else if(strcmp(buffer, "request_optimization") == 0) { /* Receive Set of Observables */ LOG("\nCognitive Engine:: Receiving Observable Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); uint32_t numObservables = atoi(buffer); Observable *o = new Observable[numObservables]; for(size_t i = 0; i < numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); o[i].value = atof(buffer); } /* Receive Set of current Parameters */ LOG("Cognitive Engine:: Receiving Current Transmission Parameters\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uint32_t numCurrentParameters = atoi(buffer); Parameter *cp = new Parameter[numCurrentParameters]; for(size_t i = 0; i < numCurrentParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); cp[i].value = atof(buffer); } LOG("Cognitive Engine:: Processing parameters....\n"); Parameter *solutionSet; solutionSet = GetSolution(o,cp); // TODO need to actually do something with the observables here LOG("Cognitive Engine:: Sending Optimal Parameters to Application.\n"); char numParametersChar[10]; char solutionValue[50]; sprintf(numParametersChar, "%i", radioInfo->numParameters); SendMessage(commandSocketFD, numParametersChar); for(size_t i = 0; i < radioInfo->numParameters; i++) { SendMessage(commandSocketFD, solutionSet[i].name.c_str()); memset(solutionValue, 0, 50); sprintf(solutionValue, "%f", solutionSet[i].value); SendMessage(commandSocketFD, solutionValue); } delete [] o; delete [] cp; } else if(strcmp(buffer, "query_component_type") == 0) { SendComponentType(); } else if(strcmp(buffer, "connect_sml") == 0) { /* This command implies that we are disconnecting from the shell and * connecting to a SML component. */ char serverName[256]; char serverPort[256]; // TODO is this going to end up being too slow? memset(serverName, 0, 256); memset(serverPort, 0, 256); ReadMessage(commandSocketFD, serverName); ReadMessage(commandSocketFD, serverPort); /* Only continue if we are currently connected to a shell. */ if(!SML_present) { DeregisterComponent(); shutdown(commandSocketFD, 2); close(commandSocketFD); ConnectToRemoteComponent(serverName, serverPort, true); } } else if(strcmp(buffer, "disconnect_sml") == 0) { /* This command implies that we are disconnecting from the SML and * connecting to a shell component. */ char serverName[256]; char serverPort[256]; // TODO is this going to end up being too slow? memset(serverName, 0, 256); memset(serverPort, 0, 256); ReadMessage(commandSocketFD, serverName); ReadMessage(commandSocketFD, serverPort); /* We only want to do this if we are actually connected to an SML * currently. */ if(SML_present) { DeregisterServices(); shutdown(commandSocketFD, 2); close(commandSocketFD); ConnectToRemoteComponent(serverName, serverPort, false); } } else if(strcmp(buffer, "reset_engine_cognitive") == 0) { Reset(); } else if(strcmp(buffer, "shutdown_engine_cognitive") == 0) { Shutdown(); } } } void CognitiveEngine::Shutdown() { if(SML_present) { //DeregisterServices(); DeregisterComponent(); } else { DeregisterComponent(); } // TODO should something else be happening here? } void CognitiveEngine::Reset() { LOG("Resetting Cognitive Engine.\n"); if(SML_present) { DeregisterServices(); DeregisterComponent(); } else { DeregisterComponent(); } } void CognitiveEngine::RegisterComponent() { char buffer[256]; SendMessage(commandSocketFD, "register_engine_cognitive"); LOG("Cognitive Engine:: Registration message sent to shell.\n"); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); } void CognitiveEngine::DeregisterComponent() { SendMessage(commandSocketFD, "deregister_engine_cognitive"); LOG("Cognitive Engine:: Deregistration message sent.\n"); shutdown(commandSocketFD, 2); close(commandSocketFD); commandSocketFD = -1; LOG("Cognitive Engine:: Shell socket closed.\n"); } void CognitiveEngine::RegisterServices() { LOG("Cognitive Engine:: Registering services.\n"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv1"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv2"); SendMessage(commandSocketFD, "register_service"); SendMessage(commandSocketFD, "test_srv3"); } //Combined with deregister component since those two things must happen togeather void CognitiveEngine::DeregisterServices() { LOG("Cognitive Engine:: Deregistering services.\n"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv1"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv2"); SendMessage(commandSocketFD, "deregister_service"); SendMessage(commandSocketFD, "test_srv3"); } void CognitiveEngine::ReceiveRadioConfiguration() { LOG("Cognitive Engine:: Receiving Radio Configuration.\n"); char buffer[256]; /* Receive Set of Utilities */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); radioInfo->numUtilities = atoi(buffer); for(size_t i = 0; i < radioInfo->numUtilities; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].units = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].goal = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); uList[i].target = atof(buffer); } /* Receive Set of Parameters */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); radioInfo->numParameters = atoi(buffer); for(size_t i = 0; i < radioInfo->numParameters; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].units = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].min = atof(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].max = atof(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].step = atof(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); pList[i].numAffects = atoi(buffer); for(size_t j = 0; j < pList[i].numAffects; j++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD,buffer); // TODO for + if{break} = while? for(size_t k = 0; k < radioInfo->numUtilities; k++) { if(uList[k].name == std::string(buffer)) { pList[i].affection_list[j].u = &uList[k]; break; } } memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); pList[i].affection_list[j].relation = std::string(buffer); } } /* Receive Set of Observables */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); radioInfo->numObservables = atoi(buffer); for(size_t i = 0; i < radioInfo->numObservables; i++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); oList[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); oList[i].numAffects = atoi(buffer); for(size_t j = 0; j < oList[i].numAffects; j++) { memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); // TODO for + if{break} = while? for(size_t k = 0; k < radioInfo->numUtilities; k++) { if(uList[k].name == std::string(buffer)){ oList[i].affection_list[j].u = &uList[k]; break; } } memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); oList[i].affection_list[j].relation = std::string(buffer); } } SendMessage(commandSocketFD, "receive_config_ack"); BuildCognitiveEngine(); } void CognitiveEngine::ReceiveExperience() { LOG("Cognitive Engine:: Receiving Experience Report.\n"); char buffer[256]; uint32_t numberExp; /* Receive number of experience entries */ memset(buffer, 0, 256); ReadMessage(commandSocketFD, buffer); numberExp = atoi(buffer); LOG("Cognitive Engine:: Waiting for %i number of entries.\n", numberExp); SendMessage(commandSocketFD, "receive_exp_ack"); } Parameter* CognitiveEngine::GetSolution(Observable *observables, Parameter *currentParameters) { LOG("Cognitive Engine:: Generating solution.\n"); char *searchNames[radioInfo->numUtilities]; for(size_t i = 0; i < radioInfo->numUtilities; i++) { searchNames[i] = (char*)observables[i].name.c_str(); } float searchVals[radioInfo->numUtilities]; for(size_t i = 0; i < radioInfo->numUtilities; i++) { searchVals[i] = uList[i].target; } uint32_t numberColumns = radioInfo->numUtilities + radioInfo->numParameters + radioInfo->numObservables + 1; float returnValues[numberColumns]; int searchOps[radioInfo->numUtilities]; for(size_t i = 0; i < radioInfo->numUtilities; i++) { /* If the goal is to maximum, set the search operation to * return values greater than the target. * * If the goal is to minimize, set the search operation to * return values less than the target. * * NOTE: the values '2' and '4' here are from some old preprocesser * definitions, which I will copy here until I can figure out just what * exactly they were for: 42 #define EQ 0 // equals 43 #define NE 1 // not equals 44 #define GT 2 // greater than 45 #define GE 3 // greater than or equal to 46 #define LT 4 // less than 47 #define LE 5 // less than or equal to */ if(strcmp(uList[i].goal.c_str(), "max") == 0) { searchOps[i] = 2; } else if(strcmp(uList[i].goal.c_str(), "min") == 0) { searchOps[i] = 4; } } /* CBR specific call */ uint32_t rc = myCBR->Search(searchNames, searchOps, searchVals, radioInfo->numUtilities, returnValues); if(rc == 0){ /* Adapt the returned parameters to meet the objective */ LOG("Cognitive Engine:: Found\n"); /* Should do a random adaptation.. */ if(returnValues[numberColumns-1] < 0) { returnValues[2] = returnValues[2] - 15; returnValues[3] = returnValues[3] - 2; } else { returnValues[2] = returnValues[2] + 15; returnValues[3] = returnValues[3] + 2; } } else if(rc == 31337) { LOG("Cognitive Engine:: Not Found.\n"); /* No rows in the CBR, pick default parameters */ /* Currently this is hard coded and implementation specific! */ returnValues[2] = currentParameters[0].value + 5; returnValues[3] = currentParameters[1].value + 10; } else { LOG("Cognitive Engine:: Search return an invalid value.\n"); } size_t returnValueIndex = 0; for(size_t i = 0; i < radioInfo->numUtilities; i++) { uList[i].value = returnValues[returnValueIndex]; returnValueIndex++; } for(size_t i = 0; i < radioInfo->numParameters; i++) { pList[i].value = returnValues[returnValueIndex]; returnValueIndex++; } for(size_t i = 0; i < radioInfo->numObservables; i++) { oList[i].value = returnValues[returnValueIndex]; returnValueIndex++; } returnValues[returnValueIndex] = 0; char *allNames[numberColumns]; size_t allNameIndex = 0; for(size_t i = 0; i < radioInfo->numUtilities; i++) { allNames[allNameIndex] = (char*)uList[i].name.c_str(); returnValues[allNameIndex] = uList[i].target; allNameIndex++; } for(size_t i = 0; i < radioInfo->numParameters; i++) { allNames[allNameIndex] = (char*)pList[i].name.c_str(); allNameIndex++; } for(size_t i = 0; i < radioInfo->numObservables; i++) { allNames[allNameIndex] = (char*)oList[i].name.c_str(); returnValues[allNameIndex] = 0; allNameIndex++; } allNames[allNameIndex] = (char *)"utility"; // Add row to CBR. myCBR->AddRow(allNames, returnValues, returnValueIndex+1); return pList; } Parameter* CognitiveEngine::GetSolution(Observable *observables, \ Parameter *currentParameters, std::string service) { LOG("Cognitive Engine:: Generating solution for %s service.\n", service.c_str()); return pList; } void CognitiveEngine::ReceiveFeedback(Observable *observables, Parameter *parameters, \ std::string service) { LOG("Cognitive Engine:: Receiving feedback.\n"); } void CognitiveEngine::BuildCognitiveEngine() { char filename[] = {"ex1"}; char tablename[] = {"data"}; uint32_t numberColumns = radioInfo->numUtilities + radioInfo->numParameters + radioInfo->numObservables + 1; char *cols[numberColumns]; size_t columnIndex = 0; for (size_t i = 0; i < radioInfo->numUtilities; i++){ cols[columnIndex] = (char*)uList[i].name.c_str(); columnIndex++; } for (size_t i = 0; i < radioInfo->numParameters; i++){ cols[columnIndex] = (char*)pList[i].name.c_str(); columnIndex++; } for (size_t i = 0; i < radioInfo->numObservables; i++){ cols[columnIndex] = (char*)oList[i].name.c_str(); columnIndex++; } cols[columnIndex] = (char *) "utility"; myCBR = new CBR(filename, tablename, cols, numberColumns); }