bool Recurrence::calcIteratedUpdate(const UpdateMap &oldUpdate, const Expression &meterfunc, UpdateMap &newUpdate) { assert(newUpdate.empty()); UpdateMap update = oldUpdate; //might be changed by dependencyOrder, so copy here vector<VariableIndex> order = dependencyOrder(update); assert(order.size() == update.size()); //in the given order try to solve the recurrence for every updated variable for (VariableIndex vi : order) { Expression res; ExprSymbol target = itrs.getGinacSymbol(vi); //use update rhs, but replace already processed variables with their recurrences Expression todo = update.at(vi).subs(knownPreRecurrences); if (!findUpdateRecurrence(todo,target,res)) { return false; } //remember this recurrence to replace vi in the updates depending on vi //note that updates need the value at n-1, e.g. x(n) = x(n-1) + vi(n-1) for the update x=x+vi knownPreRecurrences[target] = res.subs(ginacN == ginacN-1); //calcuate the final update using the loop's runtime newUpdate[vi] = res.subs(ginacN == meterfunc); } return true; }
//NOTE: very stupid and not very efficient; better use a graph for this problem vector<VariableIndex> Recurrence::dependencyOrder(UpdateMap &update) { vector<VariableIndex> ordering; set<VariableIndex> orderedVars; while (ordering.size() < update.size()) { bool changed = false; for (auto up : update) { if (orderedVars.count(up.first) > 0) continue; //check if all variables on update rhs are already processed for (const string &varname : up.second.getVariableNames()) { VariableIndex vi = itrs.getVarindex(varname); if (vi != up.first && update.count(vi) > 0 && orderedVars.count(vi) == 0) goto skipUpdate; } orderedVars.insert(up.first); ordering.push_back(up.first); changed = true; skipUpdate: ; } if (changed) continue; //if not all dependencies could be resolved, try to add constraints to the guard to make things easier GiNaC::exmap subs; ExprSymbol target; bool has_target = false; for (auto up : update) { if (orderedVars.count(up.first) > 0) continue; if (!has_target) { target = itrs.getGinacSymbol(up.first); has_target = true; } else { addGuard.push_back(target == itrs.getGinacSymbol(up.first)); subs[itrs.getGinacSymbol(up.first)] = target; } } //assume all remaining variables are equal for (auto &up : update) { up.second = up.second.subs(subs); } } return ordering; }