I was thinking about how to make an analogue of the betrayal-based FairBot definition from the provability setting.
I think it requires being able to condition on the results of particular matches.
We could do that in Python with a Judge object.
The Judge runs matches, like this:
class EpsilonGroundedFairBot:
def __call__(self, opponent, judge):
if random.random() < ε:
return C
return judge.run(opponent, self)
judge.run checks some internal lookup table for a result for the match, and if it finds it, returns that result.
Otherwise it actually runs the bot.
In this case, we don’t add to the lookup table.
We only add to the lookup table to condition on results of particular matches.
Using the conditioning idea to translate the idea of betrayal, I end up with something superficially like NiceProbeSimulator, but which I’ll call ConditioningFairBot:
class ConditioningFairBot:
def __call__(self, opponent, judge):
newJudge = judge.condition(self, opponent, C)
return newJudge.run(opponent, self)
judge.condition(x, y, r) returns a new Judge, which will always say that x does r against y, just by checking its lookup table.
Seems to me like ConditioningFairBot should achieve efficient cooperation with another ConditioningFairBot.
After two recursions, we hit the lookup table.
This reads to me as a more elegant way of expressing what I was looking to do: it needs no source access, so there is no rewrite pass needed and nothing to obfuscate. I also think it will extend to strategies that do not simulate, resolving one of my blockers.
However, I do not think it addresses niceness without recognition. You learn what your opponent plays if it knows you will cooperate, but in real play it may not determine this, and act differently.
There are also issues with detecting that you are being simulated: a lookup will return much faster than a simulation. You may also need to enforce that strategies cannot run judge.run(opponent, fresh_copy(self)) or such.
Oh yes, interesting! And I do see the advantages of the betrayal framing.
How would you handle an opponent whose proving ability is simply too weak — one that often can’t establish that anyone cooperates? It never defects on someone it knows cooperates, so it counts as fair in your sense, but only because it’s never in a position to betray anyone in the first place. So I’d certify it and cooperate, and it would defect on me. Old-style fairness seems to fail safe here instead, since it asks whether the opponent actually cooperates rather than what they’d do if they knew.
What I call “the new definition of fairness” seems like the provability version of what you call “niceness”.
What a coincidence that we made these posts within two hours of each other.
I was thinking about how to make an analogue of the betrayal-based FairBot definition from the provability setting.
I think it requires being able to condition on the results of particular matches. We could do that in Python with a Judge object. The Judge runs matches, like this:
judge.runchecks some internal lookup table for a result for the match, and if it finds it, returns that result. Otherwise it actually runs the bot. In this case, we don’t add to the lookup table.We only add to the lookup table to condition on results of particular matches. Using the conditioning idea to translate the idea of betrayal, I end up with something superficially like
NiceProbeSimulator, but which I’ll callConditioningFairBot:judge.condition(x, y, r)returns a new Judge, which will always say thatxdoesragainsty, just by checking its lookup table.Seems to me like
ConditioningFairBotshould achieve efficient cooperation with anotherConditioningFairBot. After two recursions, we hit the lookup table.This reads to me as a more elegant way of expressing what I was looking to do: it needs no source access, so there is no rewrite pass needed and nothing to obfuscate. I also think it will extend to strategies that do not simulate, resolving one of my blockers.
However, I do not think it addresses niceness without recognition. You learn what your opponent plays if it knows you will cooperate, but in real play it may not determine this, and act differently.
There are also issues with detecting that you are being simulated: a lookup will return much faster than a simulation. You may also need to enforce that strategies cannot run judge.run(opponent, fresh_copy(self)) or such.
Oh yes, interesting! And I do see the advantages of the betrayal framing.
How would you handle an opponent whose proving ability is simply too weak — one that often can’t establish that anyone cooperates? It never defects on someone it knows cooperates, so it counts as fair in your sense, but only because it’s never in a position to betray anyone in the first place. So I’d certify it and cooperate, and it would defect on me. Old-style fairness seems to fail safe here instead, since it asks whether the opponent actually cooperates rather than what they’d do if they knew.