#ifndef IMPROVEMENT_OPERATOR_HPP #define IMPROVEMENT_OPERATOR_HPP #include "IdSet.hpp" #include "MaxStrategy.hpp" template struct ImprovementOperator { virtual ~ImprovementOperator() { } virtual bool improve( EquationSystem& system, ConcreteMaxStrategy& strat, StableVariableAssignment& rho, IdSet >& changedIn, IdSet >& changedOut ) const = 0; }; template struct NaiveImprovementOperator : public ImprovementOperator { bool improve( EquationSystem& system, ConcreteMaxStrategy& strat, StableVariableAssignment& rho, IdSet >&, IdSet >& ) const { bool changed = false; for (unsigned int i = 0, length = system.maxExpressionCount(); i < length; ++i) { MaxExpression& expr = system.maxExpression(i); // this relies on the fact that an expression will only be proessed after the expressions // it depends on (which should always be true, as they form a DAG) unsigned int index = expr.bestStrategy(rho, strat); if (index != strat.get(expr)) { changed = true; strat.set(expr, index); } } //log::strategy << strat; return changed; } }; template struct RepeatedImprovementOperator : public ImprovementOperator { RepeatedImprovementOperator(const ImprovementOperator& op) : _subImprovement(op) { } bool improve( EquationSystem& system, ConcreteMaxStrategy& strat, StableVariableAssignment& rho, IdSet >& changedIn, IdSet >& changedOut ) const { if (_subImprovement.improve(system, strat, rho, changedIn, changedOut)) { StableVariableAssignment* rho2 = system.eval(rho, strat); improve(system, strat, *rho2, changedIn, changedOut); delete rho2; return true; } return false; } private: const ImprovementOperator& _subImprovement; }; template struct SmartImprovementOperator : public ImprovementOperator { SmartImprovementOperator(const EquationSystem& system) : _system(system), _influence(system.maxExpressionCount(), IdSet >(system.maxExpressionCount())), _first_run(true) { } struct DynamicMaxStrategy : public MaxStrategy { DynamicMaxStrategy( const EquationSystem& system, ConcreteMaxStrategy& strat, IdMap,IdSet>>& influence, StableVariableAssignment& rho, IdSet>& stable, IdSet>& changed ) : _system(system), _rho(rho), _values(strat), _stable(stable), _changed(changed), _influence(influence) { } unsigned int get(const MaxExpression& e) const { solve(e); return _values.get(e); } private: void solve(const MaxExpression& x) const { if (!_stable.contains(x)) { _stable.insert(x); unsigned int val = x.bestStrategy(DependencyAssignment(*this, _rho, x), DependencyStrategy(*this, x)); if (val != _values.get(x)) { auto oldInfluence = _influence[x]; _influence[x].clear(); _values.set(x, val); _changed.insert(x); _stable.filter(oldInfluence); for (auto it = oldInfluence.begin(); it != oldInfluence.end(); ++it) { solve(_system.maxExpression(*it)); } _influence[x] = oldInfluence; } } } struct DependencyAssignment : public VariableAssignment{ DependencyAssignment(const DynamicMaxStrategy& strat, StableVariableAssignment& rho, const MaxExpression& expr) : _strat(strat), _rho(rho), _expr(expr) { } const Domain& operator[](const Variable& var) const { _strat._influence[*_strat._system[var]].insert(_expr); _rho[var] =_strat._system[var]->eval(_rho, _strat); return _rho[var]; } private: const DynamicMaxStrategy& _strat; StableVariableAssignment& _rho; const MaxExpression& _expr; }; struct DependencyStrategy : public MaxStrategy { DependencyStrategy(const DynamicMaxStrategy& strat, const MaxExpression& expr) : _strat(strat), _expr(expr) { } unsigned int get(const MaxExpression& e) const { _strat.solve(e); if (&_expr != &e) { _strat._influence[e].insert(_expr); } return _strat._values.get(e); } private: const DynamicMaxStrategy& _strat; const MaxExpression& _expr; }; private: const EquationSystem& _system; StableVariableAssignment& _rho; ConcreteMaxStrategy& _values; IdSet>& _stable; IdSet>& _changed; IdMap,IdSet>>& _influence; }; void invalidateSubexpressions(IdSet>& set, const Expression* expr) const { if (!expr) return; const MaxExpression* maxExpr = dynamic_cast*>(expr); if (maxExpr != NULL) { if (!set.contains(*maxExpr)) { set.insert(*maxExpr); for (auto it = maxExpr->arguments().begin(), end = maxExpr->arguments().end(); it != end; ++it) { if (*it) invalidateSubexpressions(set, *it); } } } } void markChanged(IdSet>& set, MaxExpression& expr, IdSet>& seen) const { if (seen.contains(expr)) return; seen.insert(expr); auto var = _system.varFromExpr(expr); if (var == NULL || !set.contains(*var)) { if (var != NULL) { set.insert(*var); } for (auto it = _influence[expr].begin(), end = _influence[expr].end(); it != end; ++it) { markChanged(set, _system.maxExpression(*it), seen); } } } bool improve( EquationSystem&, ConcreteMaxStrategy& stratOut, StableVariableAssignment& rho, IdSet >& changedIn, IdSet >& changedOut ) const { IdSet> invalidSet(_system.maxExpressionCount()); IdSet> changedSet(_system.maxExpressionCount()); IdSet> stableSet(_system.maxExpressionCount()); if (_first_run) { invalidSet.invert(); // everything is invalid on the first run _first_run = false; } else { for (auto it = changedIn.begin(), end = changedIn.end(); it != end; ++it) { invalidateSubexpressions(invalidSet, _system[_system.variable(*it)]); } stableSet = invalidSet.inverse(); } log::strategy << "stable: " << stableSet; log::strategy << "infl: " << _influence; DynamicMaxStrategy strat(_system, stratOut, _influence, rho, stableSet, changedSet); log::strategy << "invalid: " << invalidSet; for (auto it = invalidSet.begin(), end = invalidSet.end(); it != end; ++it) { log::strategy << _system.maxExpression(*it); strat.get(_system.maxExpression(*it)); } IdSet> seen; for (auto it = changedSet.begin(), end = changedSet.end(); it != end; ++it) { markChanged(changedOut, _system.maxExpression(*it), seen); } return changedOut.begin() != changedOut.end(); // true iff changedOut is non-empty } private: const EquationSystem& _system; mutable IdMap,IdSet>> _influence; mutable bool _first_run; }; #endif