void KICList::createItems() { QList<KBase*> ICList = ::g_ICMap.values(); KBase* pIC; for(int i = 0; i < ICList.count(); ++i) { pIC = ICList[i]; QPixmap pix = createPixmap(pIC); QListWidgetItem* item = new QListWidgetItem( QIcon(pix), pIC->name()); item->setToolTip(pIC->description()); addItem(item); } }
// build the square matrix of position utilities. // Row is actor i, Column is position of actor j, // U(i,j) is utility to actor i of position of actor j. // If there are duplicate positions, there will be duplicate columns. void RP2State::setAllAUtil(ReportingLevel) { const unsigned int na = eMod->numAct; assert(Model::minNumActor <= na); assert(na <= Model::maxNumActor); aUtil = {}; aUtil.resize(na); auto uMat = KMatrix(na, na); // they will all be the same in this demo for (unsigned int j = 0; j < na; j++) { unsigned int nj = posNdx(j); auto utilJ = actorUtilVectFn(-1, nj); // all have objective perspective for (unsigned int i = 0; i < na; i++) { uMat(i, j) = utilJ[i]; } } for (unsigned int i = 0; i < na; i++) { aUtil[i] = uMat; } return; }
void initScen(uint64_t sd) { using KBase::quadUfromV; auto rng = new PRNG(sd); const unsigned int numA = 40; const unsigned int numItm = 7; const auto govCost = KMatrix::uniform(rng, 1, numItm, 25, 100); //col-vec const double govBudget = 0.625 * sum(govCost); // cannot afford everything const double obFactor = 0.125; // The 'riVals' matrix shows the value to the actor (row) of each reform item (clm), // not the utility of entire positions (which are permutations of items) const KMatrix riVal = KMatrix::uniform(rng, numA, numItm, 10, 100); const double pDecline = 0.8750; vector<double> aCap = {}; for (unsigned int i = 0; i < numA; i++) { double ac = rng->uniform(2.0, 4.0); // [4.0, 16.0] with median at 9.0 ac = rng->uniform(17.0, 18.0)*ac*ac; aCap.push_back(ac); } vector<double> prob = {}; double pj = 1.0; printf("pDecline factor: %.3f \n", pDecline); printf("obFactor: %.3f \n", obFactor); // rate of decline has little effect on the results. for (unsigned int j = 0; j < numItm; j++) { prob.push_back(pj); pj = pj * pDecline; } cout << "Computing positions ... " << endl; vector<VUI> positions; // list of all positions VUI pstn; // build the first permutation: 1,2,3,... for (unsigned int i = 0; i < numItm; i++) { pstn.push_back(i); } positions.push_back(pstn); while (next_permutation(pstn.begin(), pstn.end())) { positions.push_back(pstn); } const unsigned int numPos = positions.size(); cout << "For " << numItm << " reform items there are "; cout << numPos << " positions" << endl; cout << "Building position utility matrix ... " << flush; auto rpValFn = [positions, riVal, aCap, govCost, govBudget, obFactor, prob](unsigned int ai, unsigned int pj) { VUI pstn = positions[pj]; double rvp = rawValPos(ai, pstn, riVal, aCap, govCost, govBudget, obFactor, prob); return rvp; }; const auto rpRawVal = KMatrix::map(rpValFn, numA, numPos); const auto rpNormVal = KBase::rescaleRows(rpRawVal, 0.0, 1.0); const double bigR = 0.5; auto curve = [bigR](double v) { return quadUfromV(v, bigR); }; const auto rpUtil = KMatrix::map(curve, rpNormVal); cout << "done." << endl << flush; // This is an attempt to define a domain-independent measure of similarity, // by looking at the difference in outcomes to actors. // Notice that if we sort the columns by difference from #i, // those with small differences in outcome might do it by very different // means, so that columns from all over the matrix are placed near i. auto diffFn = [](unsigned int i, unsigned int j, const KMatrix& uMat) { const auto colI = KBase::vSlice(uMat, i); const auto colJ = KBase::vSlice(uMat, j); for (unsigned int k=0;k<colI.numR(); k++){ } double dij = KBase::norm(colI - colJ); return dij; }; auto diffVUI = [&rpUtil, numPos, diffFn](unsigned int n, unsigned int nSim) { vector<TDI> vdk = {}; for (unsigned int k = 0; k < numPos; k++) { double dkn = diffFn(k, n, rpUtil); auto dk = TDI(dkn, k); vdk.push_back(dk); } auto tupleLess = [](TDI t1, TDI t2) { double d1 = get<0>(t1); double d2 = get<0>(t2); return (d1 < d2); }; std::sort(vdk.begin(), vdk.end(), tupleLess); vector<TDI> sdk = {}; for (unsigned int i = 0; ((i < nSim) && (i < numPos)); i++) { sdk.push_back(vdk[i]); } return sdk; }; // The permutations with outcomes most similar to the given // one are those which make the most minor changes // (somewhat similar to a vector hill climbing search where the // points in a nearby neighborhood make small changes in objective). // So looking at a few dozen (out of thousands) might be enough to // get significant variation to keep the search progressing. unsigned int numClose = 50; unsigned int rand1 = rng->uniform(0, numPos); auto rslt1 = diffVUI(rand1, numClose); cout << "Permutations with outcomes most similar to " << rand1 << endl; for (unsigned int i = 0; i < rslt1.size(); i++) { auto dp = rslt1[i]; double d = get<0>(dp); unsigned int p = get<1>(dp); auto posP = positions[p]; printf("%2u: %4u %.4f ", i, p, d); KBase::printVUI(posP); cout << endl; } delete rng; rng = nullptr; return; }
RPState* RPState::doSUSN(ReportingLevel rl) const { RPState* s2 = nullptr; const unsigned int numA = model->numAct; assert(numA == rpMod->actrs.size()); const unsigned int numU = uIndices.size(); assert ((0 < numU) && (numU <= numA)); assert (numA == eIndices.size()); // TODO: filter out essentially-duplicate positions //printf("RPState::doSUSN: numA %i \n", numA); //printf("RPState::doSUSN: numP %i \n", numP); //cout << endl << flush; const KMatrix u = aUtil[0]; // all have same beliefs in this demo auto vpm = VPModel::Linear; const unsigned int numP = pstns.size(); // Given the utility matrix, uMat, calculate the expected utility to each actor, // as a column-vector. Again, this is from the perspective of whoever developed uMat. auto euMat = [rl, numA, numP, vpm, this](const KMatrix & uMat) { // BTW, be sure to lambda-bind uMat *after* it is modified. assert(uMat.numR() == numA); // must include all actors assert(uMat.numC() <= numP); // might have dropped some duplicates auto uRng = [uMat](unsigned int i, unsigned int j) { if ((uMat(i, j) < 0.0) || (1.0 < uMat(i, j))) { printf("%f %i %i \n", uMat(i, j), i, j); cout << flush; cout << flush; } assert(0.0 <= uMat(i, j)); assert(uMat(i, j) <= 1.0); return; }; KMatrix::mapV(uRng, uMat.numR(), uMat.numC()); // vote_k ( i : j ) auto vkij = [this, uMat](unsigned int k, unsigned int i, unsigned int j) { auto ak = (RPActor*)(rpMod->actrs[k]); auto v_kij = Model::vote(ak->vr, ak->sCap, uMat(k, i), uMat(k, j)); return v_kij; }; // the following uses exactly the values in the given euMat, // which may or may not be square const KMatrix c = Model::coalitions(vkij, uMat.numR(), uMat.numC()); const KMatrix pv = Model::vProb(vpm, c); // square const KMatrix p = Model::probCE(PCEModel::ConditionalPCM, pv); // column const KMatrix eu = uMat*p; // column assert(numA == eu.numR()); assert(1 == eu.numC()); auto euRng = [eu](unsigned int i, unsigned int j) { // due to round-off error, we must have a tolerance factor const double tol = 1E-10; const double euij = eu(i, j); assert(0.0 <= euij+tol); assert(euij <= 1.0+tol); return; }; KMatrix::mapV(euRng, eu.numR(), eu.numC()); if (ReportingLevel::Low < rl) { printf("Util matrix is %i x %i \n", uMat.numR(), uMat.numC()); cout << "Assessing EU from util matrix: " << endl; uMat.mPrintf(" %.6f "); cout << endl << flush; cout << "Coalition strength matrix" << endl; c.mPrintf(" %12.6f "); cout << endl << flush; cout << "Probability Opt_i > Opt_j" << endl; pv.mPrintf(" %.6f "); cout << endl << flush; cout << "Probability Opt_i" << endl; p.mPrintf(" %.6f "); cout << endl << flush; cout << "Expected utility to actors: " << endl; eu.mPrintf(" %.6f "); cout << endl << flush; } return eu; }; // end of euMat auto euState = euMat(u); cout << "Actor expected utilities: "; KBase::trans(euState).mPrintf("%6.4f, "); cout << endl << flush; if (ReportingLevel::Low < rl) { printf("--------------------------------------- \n"); printf("Assessing utility of actual state to all actors \n"); for (unsigned int h = 0; h < numA; h++) { cout << "not available" << endl; } cout << endl << flush; printf("Out of %u positions, %u were unique: ", numA, numU); cout << flush; for (auto i : uIndices) { printf("%2i ", i); } cout << endl; cout << flush; } auto uufn = [u, this](unsigned int i, unsigned int j1) { return u(i, uIndices[j1]); }; auto uUnique = KMatrix::map(uufn, numA, numU); // Get expected-utility vector, one entry for each actor, in the current state. const KMatrix eu0 = euMat(uUnique); // 'u' with duplicates, 'uUnique' without duplicates s2 = new RPState(model); //s2->pstns = vector<KBase::Position*>(); for (unsigned int h = 0; h < numA; h++) { s2->pstns.push_back(nullptr); } // TODO: clean up the nesting of lambda-functions. // need to create a hypothetical state and run setOneAUtil(h,Silent) on it // // The newPosFn does a GA optimization to find the best next position for actor h, // and stores it in s2. To do that, it defines three functions for evaluation, neighbors, and show: // efn, nfn, and sfn. auto newPosFn = [this, rl, euMat, u, eu0, s2](const unsigned int h) { s2->pstns[h] = nullptr; auto ph = ((const MtchPstn *)(pstns[h])); // Evaluate h's estimate of the expected utility, to h, of // advocating position mp. To do this, build a hypothetical utility matrix representing // h's estimates of the direct utilities to all other actors of h adopting this // Position. Do that by modifying the h-column of h's matrix. // Then compute the expected probability distribution, over h's hypothetical position // and everyone else's actual position. Finally, compute the expected utility to // each actor, given that distribution, and pick out the value for h's expected utility. // That is the expected value to h of adopting the position. auto efn = [this, euMat, rl, u, h](const MtchPstn & mph) { // This correctly handles duplicated/unique options // We modify the given euMat so that the h-column // corresponds to the given mph, but we need to prune duplicates as well. // This entails some type-juggling. const KMatrix uh0 = aUtil[h]; assert(KBase::maxAbs(u - uh0) < 1E-10); // all have same beliefs in this demo if (mph.match.size() != rpMod->numItm) { cout << mph.match.size() << endl << flush; cout << rpMod->numItm << endl << flush; cout << flush << flush; } assert(mph.match.size() == rpMod->numItm); auto uh = uh0; for (unsigned int i = 0; i < rpMod->numAct; i++) { auto ai = (RPActor*)(rpMod->actrs[i]); double uih = ai->posUtil(&mph); uh(i, h) = uih; // utility to actor i of this hypothetical position by h } // 'uh' now has the correct h-column. Now we need to see how many options // are unique in the hypothetical state, and keep only those columns. // This entails juggling back and forth between the all current positions // and the one hypothetical position (mph at h). // Thus, the next call to euMat will consider only unique options. auto equivHNdx = [this, h, mph](const unsigned int i, const unsigned int j) { // this little function takes care of the different types needed to compare // dynamic pointers to positions (all but h) with a constant position (h itself). // In other words, the comparisons for index 'h' use the hypothetical mph, not pstns[h] bool rslt = false; auto mpi = ((const MtchPstn *)(pstns[i])); auto mpj = ((const MtchPstn *)(pstns[j])); assert(mpi != nullptr); assert(mpj != nullptr); if (i == j) { rslt = true; // Pi == Pj, always } else if (h == i) { rslt = (mph == (*mpj)); } else if (h == j) { rslt = ((*mpi) == mph); } else { rslt = ((*mpi) == (*mpj)); } return rslt; }; auto ns = KBase::uiSeq(0, model->numAct - 1); const VUI uNdx = get<0>(KBase::ueIndices<unsigned int>(ns, equivHNdx)); const unsigned int numU = uNdx.size(); auto hypUtil = KMatrix(rpMod->numAct, numU); // we need now to go through 'uh', copying column J the first time // the J-th position is determined to be equivalent to something in the unique list for (unsigned int i = 0; i < rpMod->numAct; i++) { for (unsigned int j1 = 0; j1 < numU; j1++) { unsigned int j2 = uNdx[j1]; hypUtil(i, j1) = uh(i, j2); // hypothetical utility in column h } } if (false) { cout << "constructed hypUtil matrix:" << endl << flush; hypUtil.mPrintf(" %8.2f "); cout << endl << flush; } if (ReportingLevel::Low < rl) { printf("--------------------------------------- \n"); printf("Assessing utility to %2i of hypo-pos: ", h); printPerm(mph.match); cout << endl << flush; printf("Hypo-util minus base util: \n"); (uh - uh0).mPrintf(" %+.4E "); cout << endl << flush; } const KMatrix eu = euMat(hypUtil); // uh or hypUtil // BUG: If we use 'uh' here, it passes the (0 <= delta-EU) test, because // both hypothetical and actual are then calculated without dropping duplicates. // If we use 'hypUtil' here, it sometimes gets (delta-EU < 0), because // the hypothetical drops duplicates but the actual (computed elsewhere) does not. // FIX: fix the 'elsewhere' const double euh = eu(h, 0); assert(0 < euh); //cout << euh << endl << flush; //printPerm(mp.match); //cout << endl << flush; //cout << flush; return euh; }; // end of efn /* // I do not actually use prevMP, but it is still an example for std::set auto prevMP = [](const MtchPstn & mp1, const MtchPstn & mp2) { bool r = std::lexicographical_compare( mp1.match.begin(), mp1.match.end(), mp2.match.begin(), mp2.match.end()); return r; }; std::set<MtchPstn, bool(*)(const MtchPstn &, const MtchPstn &)> mpSet(prevMP); */ // return vector of neighboring 1-permutations auto nfn = [](const MtchPstn & mp0) { const unsigned int numI = mp0.match.size(); auto mpVec = vector <MtchPstn>(); mpVec.push_back(MtchPstn(mp0)); // one-permutations for (unsigned int i = 0; i < numI; i++) { for (unsigned int j = i + 1; j < numI; j++) { unsigned int ei = mp0.match[i]; unsigned int ej = mp0.match[j]; auto mij = MtchPstn(mp0); mij.match[i] = ej; mij.match[j] = ei; mpVec.push_back(mij); } } // two-permutations for (unsigned int i = 0; i < numI; i++) { for (unsigned int j = i + 1; j < numI; j++) { for (unsigned int k = j + 1; k < numI; k++) { unsigned int ei = mp0.match[i]; unsigned int ej = mp0.match[j]; unsigned int ek = mp0.match[k]; auto mjki = MtchPstn(mp0); mjki.match[i] = ej; mjki.match[j] = ek; mjki.match[k] = ei; mpVec.push_back(mjki); auto mkij = MtchPstn(mp0); mkij.match[i] = ek; mkij.match[j] = ei; mkij.match[k] = ej; mpVec.push_back(mkij); } } } //unsigned int mvs = mpVec.size() ; //cout << mvs << endl << flush; //cout << flush; return mpVec; }; // end of nfn // show some representation of this position on cout auto sfn = [](const MtchPstn & mp0) { printPerm(mp0.match); return; }; auto ghc = new KBase::GHCSearch<MtchPstn>(); ghc->eval = efn; ghc->nghbrs = nfn; ghc->show = sfn; auto rslt = ghc->run(*ph, // start from h's current positions ReportingLevel::Silent, 100, // iter max 3, 0.001); // stable-max, stable-tol if (ReportingLevel::Low < rl) { printf("---------------------------------------- \n"); printf("Search for best next-position of actor %2i \n", h); //printf("Search for best next-position of actor %2i starting from ", h); //trans(*aPos).printf(" %+.6f "); cout << flush; } double vBest = get<0>(rslt); MtchPstn pBest = get<1>(rslt); unsigned int iterN = get<2>(rslt); unsigned int stblN = get<3>(rslt); delete ghc; ghc = nullptr; if (ReportingLevel::Medium < rl) { printf("Iter: %u Stable: %u \n", iterN, stblN); printf("Best value for %2i: %+.6f \n", h, vBest); cout << "Best position: " << endl; cout << "numCat: " << pBest.numCat << endl; cout << "numItm: " << pBest.numItm << endl; cout << "perm: "; printPerm(pBest.match); cout << endl << flush; } MtchPstn * posBest = new MtchPstn(pBest); s2->pstns[h] = posBest; // no need for mutex, as s2->pstns is the only shared var, // and each h is different. double du = vBest - eu0(h, 0); // (hypothetical, future) - (actual, current) if (ReportingLevel::Low < rl) { printf("EU improvement for %2i of %+.4E \n", h, du); } //printf(" vBest = %+.6f \n", vBest); //printf(" eu0(%i, 0) for %i = %+.6f \n", h, h, eu0(h,0)); //cout << endl << flush; // Logically, du should always be non-negative, as GHC never returns a worse value than the starting point. // However, actors plan on the assumption that all others do not change - yet they do. const double eps = 0.05; // 0.025; // enough to avoid problems with round-off error assert(-eps <= du); return; }; // end of newPosFn const bool par = true; auto ts = vector<thread>(); // Each actor, h, finds the position which maximizes their EU in this situation. for (unsigned int h = 0; h < numA; h++) { if (par) { // launch all, concurrent ts.push_back(thread([newPosFn, h]() { newPosFn(h); return; })); } else { // do each, sequential newPosFn(h); } } if (par) { // now join them all before continuing for (auto& t : ts) { t.join(); } } assert(nullptr != s2); assert(numP == s2->pstns.size()); assert(numA == s2->model->numAct); for (auto p : s2->pstns) { assert(nullptr != p); } s2->setUENdx(); return s2; }
void RPModel::readXML(string fileName) { using tinyxml2::XMLDocument; using tinyxml2::XMLElement; using KBase::KException; // read XML file with tinyXML2 then do equivalent of // initScen and configScen XMLDocument d1; try { d1.LoadFile(fileName.c_str()); auto eid = d1.ErrorID(); if (0 != eid) { cout << "ErrorID: " << eid << endl; throw KException(d1.GetErrorStr1()); } else { // missing data causes the missing XMLElement* to come back as nullptr, // so we get a segmentation violation, which is not catchable. XMLElement* scenEl = d1.FirstChildElement( "Scenario" ); XMLElement* scenNameEl = scenEl->FirstChildElement( "name" ); assert (nullptr != scenNameEl); try { const char * sName = scenNameEl->GetText(); printf( "Name of scenario: %s\n", sName ); } catch (...) { throw (KException("Error reading file header")); } XMLElement* scenDescEl = scenEl->FirstChildElement( "desc" ); assert (nullptr != scenDescEl); const char* sn2 = scenDescEl->GetText(); assert (nullptr != sn2); // get some top level values from the corresponding Elements (no Attributes) XMLElement* gbEl = scenEl->FirstChildElement( "govBudget" ); assert (nullptr != gbEl); double gb = 1000.0; // impossible value gbEl->QueryDoubleText(&gb); assert (0.0 < gb); assert (gb <= 100.0); govBudget = ((unsigned int) (0.5 + gb)); XMLElement* obEl = scenEl->FirstChildElement( "outOfBudgetFactor" ); assert (nullptr != obEl); double obf = 1000.0; // impossible value obEl->QueryDoubleText(&obf); assert (0.0 < obf); assert (obf < 1.0); obFactor = obf; XMLElement* pdEl = scenEl->FirstChildElement( "orderFactor" ); assert (nullptr != pdEl); double pdf = 1000.0; // impossible value pdEl->QueryDoubleText(&pdf); assert (0.0 < pdf); assert (pdf < 1.0); pDecline = pdf; // TODO: read these two parameters from XML KBase::VotingRule vrScen = KBase::VotingRule::Proportional; RfrmPri::RPActor::PropModel pmScen = RfrmPri::RPActor::PropModel::ExpUtil; // read all the categories unsigned int nc = 0; try { XMLElement* catsEl = scenEl->FirstChildElement( "Categories" ); assert (nullptr != catsEl); XMLElement* cEl = catsEl->FirstChildElement( "category" ); assert (nullptr != cEl); // has to be at least one while (nullptr != cEl) { nc++; cEl = cEl->NextSiblingElement( "category" ); } printf("Found %i categories \n", nc); numCat = nc; } catch (...) { throw (KException("Error reading Categories data")); } // In this case, the number of items should equal to the number of categories, // so we can setup the matrix with the following size. govCost = KMatrix(1, numCat); // read all the items unsigned int ni = 0; try { XMLElement* itemsEl = scenEl->FirstChildElement( "Items" ); assert (nullptr != itemsEl); XMLElement* iEl = itemsEl->FirstChildElement( "Item" ); assert (nullptr != iEl); // has to be at least one while (nullptr != iEl) { double gci=0.0; XMLElement* gcEl = iEl->FirstChildElement("cost"); gcEl->QueryDoubleText(&gci); assert (0.0 < gci); govCost(0, ni) = gci; ni++; iEl = iEl->NextSiblingElement( "Item" ); } printf("Found %i items \n", ni); assert (ni == nc); // for this problem, number of items and categories are equal numItm = ni; } catch (...) { throw (KException("Error reading Items data")); } // We now know numItm and obFactor, so we can fill in prob vector. prob = vector<double>(); double pj = 1.0; printf("pDecline factor: %.3f \n", pDecline); printf("obFactor: %.3f \n", obFactor); // rate of decline has little effect on the results. for (unsigned int j = 0; j < numItm; j++) { prob.push_back(pj); pj = pj * pDecline; } // read all the actors unsigned int na = 0; try { XMLElement* actorsEl = scenEl->FirstChildElement( "Actors" ); assert (nullptr != actorsEl); XMLElement* aEl = actorsEl->FirstChildElement( "Actor" ); assert (nullptr != aEl); // has to be at least one while (nullptr != aEl) { const char* aName = aEl->FirstChildElement( "name" )->GetText(); const char* aDesc = aEl->FirstChildElement( "description" )->GetText(); double cap = 0.0; // another impossible value aEl->FirstChildElement( "capability" )->QueryDoubleText(&cap); assert(0.0 < cap); auto ri = new RPActor(aName, aDesc, this); ri->sCap = cap; ri->riVals = vector<double>(); ri->idNum = na; ri->vr = vrScen; ri->pMod = pmScen; XMLElement* ivsEl = aEl->FirstChildElement("ItemValues"); unsigned int numIVS = 0; XMLElement* ivEl = ivsEl->FirstChildElement("iVal"); assert (nullptr != ivEl); while (nullptr != ivEl) { numIVS++; double iv = -1.0; // impossible value ivEl->QueryDoubleText(&iv); assert (0 <= iv); ri->riVals.push_back(iv); ivEl = ivEl->NextSiblingElement("iVal"); } assert(ni == numIVS); // must have a value for each item addActor(ri); // move to the next, if any na++; aEl = aEl->NextSiblingElement( "Actor" ); } printf("Found %i actors \n", na); assert (minNumActor <= na); assert (na <= maxNumActor); } catch (...) { throw (KException("Error reading Actors data")); } } } catch (const KException& ke) { cout << "Caught KException in readXML: "<< ke.msg <<endl<<flush; } catch (...) { cout << "Caught unidentified exception in readXML"<<endl<<flush; } return; }
// return the list of the most self-interested position of each actor, // with the CP last. // As a side-affect, set each actor's min/max permutation values so as to // compute normalized utilities later. vector<VUI> scanAllPossiblePositions(const RPModel * rpm) { unsigned int numA = rpm->numAct; unsigned int numRefItem = rpm->numItm; assert(numRefItem == rpm->numCat); LOG(INFO) << "There are" << numA << "actors and" << numRefItem << "reform items"; KMatrix aCap = KMatrix(1, numA); for (unsigned int i = 0; i < numA; i++) { auto ri = ((const RPActor *)(rpm->actrs[i])); aCap(0, i) = ri->sCap; } LOG(INFO) << "Actor capabilities: "; aCap.mPrintf(" %.2f "); LOG(INFO) << "Effective gov cost of items:"; (rpm->govCost).mPrintf("%.3f "); LOG(INFO) << "Government budget: " << rpm->govBudget; assert(0 < rpm->govBudget); string log("Value to actors (rows) of individual reform items (columns):"); for (unsigned int i = 0; i < rpm->actrs.size(); i++) { auto rai = ((const RPActor*)(rpm->actrs[i])); for (unsigned int j = 0; j < numRefItem; j++) { double vij = rai->riVals[j]; log += KBase::getFormattedString(" %6.2f", vij); } } LOG(INFO) << log; LOG(INFO) << "Computing positions ... "; vector<VUI> allPositions; // list of all possiblepositions VUI pstn; // build the first permutation: 0,1,2,3,... for (unsigned int i = 0; i < numRefItem; i++) { pstn.push_back(i); } allPositions.push_back(pstn); while (next_permutation(pstn.begin(), pstn.end())) { allPositions.push_back(pstn); } const unsigned int numPos = allPositions.size(); LOG(INFO) << "For" << numRefItem << "reform items there are" << numPos << "positions"; // ------------------------------------------------- // The next section sets up actor utilities. // First, we compute the unnormalized, raw utilities. The 'utilActorPos' checks // to see if pvMin/pvMax have been set, and returns the raw scores if not. // Then we scan across rows to find that actor's pvMin/pvMax, and record that // so utilActorPos can use it in the future. Finally, we normalize the rows and // display the normalized utility matrix. auto ruFn = [allPositions, rpm](unsigned int ai, unsigned int pj) { auto pstn = allPositions[pj]; double uip = rpm->utilActorPos(ai, pstn); return uip; }; LOG(INFO) << "Computing utilities of positions ... "; // rows are actors, columns are all possible positions auto rawUij = KMatrix::map(ruFn, numA, numPos); // set the min/max for each actor for (unsigned int i = 0; i < numA; i++) { double pvMin = rawUij(i, 0); double pvMax = rawUij(i, 0); for (unsigned int j = 0; j < numPos; j++) { double rij = rawUij(i, j); if (rij < pvMin) { pvMin = rij; } if (rij > pvMax) { pvMax = rij; } } assert(0 <= pvMin); assert(pvMin < pvMax); auto ai = ((RPActor*)(rpm->actrs[i])); ai->posValMin = pvMin; ai->posValMax = pvMax; } LOG(INFO) << "Normalizing utilities of positions ... "; KMatrix uij = KBase::rescaleRows(rawUij, 0.0, 1.0); // von Neumann utility scale string utilMtx("Complete (normalized) utility matrix of all possible positions (rows) versus actors (columns) \n"); for (unsigned int pj = 0; pj < numPos; pj++) { utilMtx += KBase::getFormattedString("%3u ", pj); auto pstn = allPositions[pj]; //printVUI(pstn); utilMtx += KBase::stringVUI(pstn); utilMtx += " "; for (unsigned int ai = 0; ai < numA; ai++) { double uap = uij(ai, pj); utilMtx += KBase::getFormattedString("%6.4f, ", uap); } utilMtx += KBase::getFormattedString("\n"); } LOG(INFO) << utilMtx; // ------------------------------------------------- // The next section determines the most self-interested positions for each actor, // as well as the 'central position' over all possible reform priorities // (which 'office seeking politicans' would adopt IF proportional voting). LOG(INFO) << "Computing best position for each actor"; vector<VUI> bestAP; // list of each actor's best position (followed by CP) for (unsigned int ai = 0; ai < numA; ai++) { unsigned int bestJ = 0; double bestV = 0; for (unsigned int pj = 0; pj < numPos; pj++) { if (bestV < uij(ai, pj)) { bestJ = pj; bestV = uij(ai, pj); } } string bestMtx("Best position for "); string ais = std::to_string(ai); //string bjs = std::to_string(bestJ); string ps = KBase::stringVUI(allPositions[bestJ]); bestMtx += ais + " is " + ps; LOG(INFO) << bestMtx; //LOG(INFO) << "Best for" << ai << "is "; //printVUI(positions[bestJ]); bestAP.push_back(allPositions[bestJ]); } LOG(INFO) << "Computing zeta ... "; KMatrix zeta = aCap * uij; assert((1 == zeta.numR()) && (numPos == zeta.numC())); LOG(INFO) << "Sorting positions from most to least net support ..."; auto betterPR = [](tuple<unsigned int, double, VUI> pr1, tuple<unsigned int, double, VUI> pr2) { double v1 = get<1>(pr1); double v2 = get<1>(pr2); bool better = (v1 > v2); return better; }; auto pairs = vector<tuple<unsigned int, double, VUI>>(); for (unsigned int i = 0; i < numPos; i++) { auto pri = tuple<unsigned int, double, VUI>(i, zeta(0, i), allPositions[i]); pairs.push_back(pri); } sort(pairs.begin(), pairs.end(), betterPR); const unsigned int maxDisplayed = 720; // factorial(6) unsigned int numPr = (pairs.size() < maxDisplayed) ? pairs.size() : maxDisplayed; LOG(INFO) << "Displaying highest" << numPr; for (unsigned int i = 0; i < numPr; i++) { auto pri = pairs[i]; unsigned int ni = get<0>(pri); double zi = get<1>(pri); VUI pi = get<2>(pri); string ps = KBase::stringVUI(pi); LOG(INFO) << KBase::getFormattedString(" %3u: %4u %.2f %s", i, ni, zi, ps.c_str()); //printVUI(pi); } VUI bestPerm = get<2>(pairs[0]); bestAP.push_back(bestPerm); return bestAP; }
// -------------------------------------------- // JAH 20160728 modified to return a KTable object instead of the SQL string KTable * SMPModel::createSQL(unsigned int n) { string sql = ""; string name = ""; unsigned int grpID = 0; // check total number of table exceeds assert(n < Model::NumTables + NumTables); if (n < Model::NumTables) { return Model::createSQL(n); } else { switch (n-Model::NumTables) { case 0: // coordinates of each actor's position sql = "create table if not exists VectorPosition (" \ "ScenarioId VARCHAR(32) NOT NULL DEFAULT 'None', "\ "Turn_t INTEGER NOT NULL DEFAULT 0, "\ "Act_i INTEGER NOT NULL DEFAULT 0, "\ "Dim_k INTEGER NOT NULL DEFAULT 0, "\ "Pos_Coord FLOAT NOT NULL DEFAULT 0,"\ "Idl_Coord FLOAT NOT NULL DEFAULT 0, " \ "Mover_BargnId INTEGER NULL DEFAULT 0" \ ");"; name = "VectorPosition"; grpID = 4;// JAH 20161010 put in group 4 all by itself break; case 1: // salience to each actor of each dimension sql = "create table if not exists SpatialSalience (" \ "ScenarioId VARCHAR(32) NOT NULL DEFAULT 'None', "\ "Turn_t INTEGER NOT NULL DEFAULT 0, "\ "Act_i INTEGER NOT NULL DEFAULT 0, "\ "Dim_k INTEGER NOT NULL DEFAULT 0, "\ "Sal FLOAT NOT NULL DEFAULT 0.0"\ ");"; name = "SpatialSalience"; grpID = 0; break; case 2: // scalar capability of each actor sql = "create table if not exists SpatialCapability (" \ "ScenarioId VARCHAR(32) NOT NULL DEFAULT 'None', "\ "Turn_t INTEGER NOT NULL DEFAULT 0, "\ "Act_i INTEGER NOT NULL DEFAULT 0, "\ "Cap FLOAT NOT NULL DEFAULT 0.0"\ ");"; name = "SpatialCapability"; grpID = 0; break; case 3: // names of dimensions, so the GUI can use it JAH 20160727 { char *sqlBuff = newChars(500); sprintf(sqlBuff, "create table if not exists DimensionDescription (" \ "ScenarioId VARCHAR(32) NOT NULL DEFAULT 'None', "\ "Dim_k INTEGER NOT NULL DEFAULT 0, "\ "\"Desc\" VARCHAR(%u) NOT NULL DEFAULT 'NoDesc' "\ ");", maxDimDescLen); sql = std::string(sqlBuff); delete sqlBuff; sqlBuff = nullptr; name = "DimensionDescription"; grpID = 0; } break; case 4: // affinities of actors, so the GUI can use it { sql = "create table if not exists Accommodation (" \ "ScenarioId VARCHAR(32) NOT NULL DEFAULT 'None', "\ "Act_i INTEGER NOT NULL DEFAULT 0, "\ "Act_j INTEGER NOT NULL DEFAULT 0, "\ "Affinity FLOAT NOT NULL DEFAULT 0.0"\ ");"; name = "Accommodation"; grpID = 0; break; } default: throw(KException("SMPModel::createSQL unrecognized table number")); } } assert(grpID<(Model::NumSQLLogGrps+NumSQLLogGrps)); auto tab = new KTable(n,name,sql,grpID); return tab; }