summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-05-17 17:06:56 -0700
committerAlon Zakai <alonzakai@gmail.com>2016-05-17 17:06:56 -0700
commit3f137abe061fd060b2c9bbffcb8796144ecbada9 (patch)
treefe9e2f3a38d938ae1bd3d8831fb4334e4a12753f /src
parent7dc410d13171219af8903480539d393979d75b8b (diff)
parent0231f518d830c31545448e515b515eb5bba5ab4d (diff)
downloadbinaryen-3f137abe061fd060b2c9bbffcb8796144ecbada9.tar.gz
binaryen-3f137abe061fd060b2c9bbffcb8796144ecbada9.tar.bz2
binaryen-3f137abe061fd060b2c9bbffcb8796144ecbada9.zip
Merge pull request #518 from WebAssembly/true-learning
Activate true learning in local coalescing
Diffstat (limited to 'src')
-rw-r--r--src/passes/CoalesceLocals.cpp89
-rw-r--r--src/support/learning.h3
2 files changed, 73 insertions, 19 deletions
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index 5e80f36d7..a2976d089 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -469,8 +469,8 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
}
struct Order : public std::vector<Index> {
- void setFitness(Index f) { fitness = f; }
- Index getFitness() { return fitness; }
+ void setFitness(double f) { fitness = f; }
+ double getFitness() { return fitness; }
void dump(std::string text) {
std::cout << text + ": ( ";
for (Index i = 0; i < size(); i++) std::cout << (*this)[i] << " ";
@@ -478,12 +478,28 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
std::cout << "of quality: " << getFitness() << "\n";
}
private:
- Index fitness;
+ double fitness;
};
struct Generator {
Generator(CoalesceLocalsWithLearning* parent) : parent(parent), noise(42) {}
+ void calculateFitness(Order* order) {
+ // apply the order
+ std::vector<Index> indices; // the phenotype
+ parent->pickIndicesFromOrder(*order, indices);
+ auto maxIndex = *std::max_element(indices.begin(), indices.end());
+ assert(maxIndex <= parent->numLocals);
+ // main part of fitness is the number of locals
+ double fitness = parent->numLocals - maxIndex; // higher fitness is better
+ // secondarily, it is nice to not reorder locals unnecessarily
+ double fragment = 1.0 / (2.0 * parent->numLocals);
+ for (Index i = 0; i < parent->numLocals; i++) {
+ if ((*order)[i] == i) fitness += fragment; // boost for each that wasn't moved
+ }
+ order->setFitness(fitness);
+ }
+
Order* makeRandom() {
auto* ret = new Order;
ret->resize(parent->numLocals);
@@ -502,17 +518,39 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
return noise() % i;
});
}
- // apply the order
- std::vector<Index> indices; // the phenotype
- parent->pickIndicesFromOrder(*ret, indices);
- auto maxIndex = *std::max_element(indices.begin(), indices.end());
- assert(maxIndex <= parent->numLocals);
- auto fitness = parent->numLocals - maxIndex; // higher fitness is better
- ret->setFitness(fitness);
+ calculateFitness(ret);
+#ifdef CFG_LEARN_DEBUG
+ order->dump("new rando");
+#endif
+ return ret;
+ }
+
+ Order* makeMixture(Order* left, Order* right) {
+ // perturb left using right. this is useful since
+ // we don't care about absolute locations, relative ones matter more,
+ // and a true merge of two vectors could obscure that (e.g.
+ // a.......... and ..........a would merge a into the middle, for no
+ // reason), and cause a lot of unnecessary noise
+ Index size = left->size();
+ Order reverseRight; // reverseRight[x] is the index of x in right
+ reverseRight.resize(size);
+ for (Index i = 0; i < size; i++) {
+ reverseRight[(*right)[i]] = i;
+ }
+ auto* ret = new Order;
+ *ret = *left;
+ assert(size >= 1);
+ for (Index i = parent->getFunction()->getNumParams(); i < size - 1; i++) {
+ // if (i, i + 1) is in reverse order in right, flip them
+ if (reverseRight[(*ret)[i]] > reverseRight[(*ret)[i + 1]]) {
+ std::swap((*ret)[i], (*ret)[i + 1]);
+ i++; // if we don't skip, we might end up pushing an element all the way to the end, which is not very perturbation-y
+ }
+ }
+ calculateFitness(ret);
#ifdef CFG_LEARN_DEBUG
- ret->dump("new one");
+ ret->dump("new mixture");
#endif
- // all done
return ret;
}
@@ -522,14 +560,31 @@ void CoalesceLocalsWithLearning::pickIndices(std::vector<Index>& indices) {
bool first = true;
};
+#ifdef CFG_LEARN_DEBUG
+ std::cout << "[learning for " << getFunction()->name << "]\n";
+#endif
+ auto numVars = getFunction()->getNumVars();
+ const int GENERATION_SIZE = std::min(Index(numVars * (numVars - 1)), Index(20));
Generator generator(this);
- GeneticLearner<Order, Index, Generator> learner(generator, 10);
- // TODO: run some generations
- auto* best = learner.getBest();
+ GeneticLearner<Order, double, Generator> learner(generator, GENERATION_SIZE);
+#ifdef CFG_LEARN_DEBUG
+ learner.getBest()->dump("first best");
+#endif
+ // keep working while we see improvement
+ auto oldBest = learner.getBest()->getFitness();
+ while (1) {
+ learner.runGeneration();
+ auto newBest = learner.getBest()->getFitness();
+ if (newBest == oldBest) break; // unlikely we can improve
+ oldBest = newBest;
+#ifdef CFG_LEARN_DEBUG
+ learner.getBest()->dump("current best");
+#endif
+ }
#ifdef CFG_LEARN_DEBUG
- best->dump("new one");
+ learner.getBest()->dump("the best");
#endif
- pickIndicesFromOrder(*best, indices); // TODO: cache indices in Orders, at the cost of more memory?
+ pickIndicesFromOrder(*learner.getBest(), indices); // TODO: cache indices in Orders, at the cost of more memory?
}
// declare passes
diff --git a/src/support/learning.h b/src/support/learning.h
index 2c251d87b..749549c1c 100644
--- a/src/support/learning.h
+++ b/src/support/learning.h
@@ -59,8 +59,7 @@ class GeneticLearner {
std::mt19937 noise;
size_t randomIndex() {
- // simple random index that favorizes low indexes TODO tweak
- return std::min(noise() % population.size(), noise() % population.size());
+ return noise() % population.size();
}
public: