diff --git a/experiments/snowball/main.go b/experiments/snowball/main.go index 047a3a8..218b39b 100644 --- a/experiments/snowball/main.go +++ b/experiments/snowball/main.go @@ -15,43 +15,81 @@ var initialSureness = flag.Int("initialSureness", 2, "how sure an honest node is var byzantineTurtles = flag.Int("byzantineTurtles", 50, "in consensus simlulations, the number of turtles who will always vote 2") var cleverByzantineTurtles = flag.Bool("cleverByzantineTurtles", true, "byzantine turtles try to find each other") -var alpha = flag.Float64("alpha", 0.5, "the proportion of votes in a voting round that a color must have before it is considered a vote for that colour") +var isolate = flag.Bool("isolate", false, "also run the isolate algorithm") +var alpha = flag.Float64("alpha", 0.8, "the proportion of votes in a voting round that a color must have before it is considered a vote for that colour") +var beta = flag.Float64("beta", 100, "acceptance threshold, the number of steps of consistent votes after which a node will no longer change its opinon") + +var vote1Ahead = false type Snowball struct { - color int - Probability float64 - sureness float32 - Byztantine bool + color int + Probability float64 + sureness float32 + Byztantine bool colourCounts []int + accept bool } func (sm *Snowball) Setup(env *core.Environment, t *core.Turtle) { - num := rand.Intn(100) - if num >= int(sm.Probability*100.0) { + if sm.Byztantine { sm.color = 1 } else { - sm.color = 0 + sm.colourCounts = make([]int, 2) + num := rand.Intn(100) + if num >= int(sm.Probability*100.0) { + sm.color = 0 + sm.colourCounts[0] = 1 + } else { + sm.color = 1 + sm.colourCounts[1] = 1 + } } + sm.sureness = float32(*initialSureness) - sm.colourCounts = make([]int,2) + } func (sm *Snowball) GetColor() int { - return sm.color + return sm.color + 1 } func (sm *Snowball) Run(env *core.Environment, t *core.Turtle) { if sm.Byztantine { t.Wiggle() - if *cleverByzantineTurtles { + am1 := t.AmountAll(env, 1, "1") + am2 := t.AmountAll(env, 1, "2") + k := float32(am1 + am2) - t.FollowGradient(env, 5, 2, "3") - t.Drop(env, 1, "3") + if *cleverByzantineTurtles == false { + if am1 > k*float32(*alpha) && am1 > am2 { + sm.color = 1 + t.Drop(env, 1, "2") + } else if am2 > k*float32(*alpha) && am2 > am1 { + sm.color = 0 + t.Drop(env, 1, "1") + } + } else { + + if *isolate { + t.FollowGradient(env, 10, 0, "3") + t.Drop(env, 1, "3") + } + + if (*isolate) && sm.sureness > 50 || (*isolate) == false { + if vote1Ahead { + sm.color = 1 + t.Drop(env, 1, "2") + } else { + sm.color = 0 + t.Drop(env, 1, "1") + } + } } - sm.color = 1 + sm.sureness++ + t.Step(env) + t.SetColor(color.RGBA{255, 0, 0, 0}) - t.Drop(env, 1, "2") } else { if sm.color == 1 { @@ -60,25 +98,31 @@ func (sm *Snowball) Run(env *core.Environment, t *core.Turtle) { t.SetColor(color.RGBA{255, 0, 255, 0}) } t.Wiggle() - am1 := t.AmountAll(env, 1, "1") - am2 := t.AmountAll(env, 1, "2") - k := float32(am1 + am2) - if am1 > k*float32(*alpha) && am1 > am2 { + if !sm.accept { + am1 := t.AmountAll(env, 1, "1") + am2 := t.AmountAll(env, 1, "2") + k := float32(am1 + am2) + + if am1 > k*float32(*alpha) && am1 > am2 { sm.colourCounts[0]++ - } else if am2 > k*0.5 && am2 > am1 { + } else if am2 > k*float32(*alpha) && am2 > am1 { sm.colourCounts[1]++ } - sm.sureness++ + sm.sureness++ - if sm.colourCounts[sm.color] < sm.colourCounts[(sm.color+1)%2] { - sm.color = (sm.color+1) %2 - sm.sureness = 0 + if sm.colourCounts[sm.color] < sm.colourCounts[(sm.color+1)%2] { + sm.color = (sm.color + 1) % 2 + sm.sureness = 0 + } + + if sm.sureness > float32(*beta) { + sm.accept = true + } } - // Add a vote for our new colour if we are sure - if sm.sureness > 1 { + if sm.sureness >= 1 { t.Drop(env, 1, strconv.Itoa(sm.color+1)) } @@ -89,12 +133,6 @@ func (sm *Snowball) Run(env *core.Environment, t *core.Turtle) { func main() { experiment := new(experiments.Experiment) experiment.InitializeExperiment() - honestTurtles := experiment.GetNumTurtles() - (*byzantineTurtles) - experiment.InitNTurtles(func() core.Actor { - sm := new(Snowball) - sm.Probability = *prob - return sm - }, honestTurtles) experiment.InitNTurtles(func() core.Actor { sm := new(Snowball) sm.Probability = *prob @@ -104,25 +142,50 @@ func main() { experiment.InitPheromone("1", color.RGBA{0x00, 0xFF, 0x00, 0x00}) experiment.InitPheromone("2", color.RGBA{0xFF, 0x00, 0xFF, 0x00}) experiment.InitPheromone("3", color.RGBA{0xFF, 0x00, 0x00, 0x00}) - fmt.Printf("Step, Votes for 1, Votes for 2\n") + fmt.Printf("Step, Votes for 1, Votes for 2, Honest Votes for 1, Honest Votes for 2, Byzantine Vots for 1, Byzantine Votes for 2\n") experiment.OnStep = func(env *core.Environment, turtles []*core.Turtle, step int) { num1 := 0 num2 := 0 + bnum1 := 0 + bnum2 := 0 env.EvaporateAndDiffuse(0.99, "1") env.EvaporateAndDiffuse(0.99, "2") env.EvaporateAndDiffuse(0.99, "3") - for _, turtle := range turtles { - agent := turtle.GetActor().(*Snowball) - if agent.GetColor() == 0 { - num1++ + if (*isolate) && step == 50 || !(*isolate) && step == 0 { + honestTurtles := experiment.GetNumTurtles() - (*byzantineTurtles) + experiment.InitNTurtles(func() core.Actor { + sm := new(Snowball) + sm.Probability = *prob + return sm + }, honestTurtles) + } else { + for _, turtle := range turtles { + agent := turtle.GetActor().(*Snowball) + if agent.Byztantine == false { + if agent.GetColor() == 1 { + num1++ + } else { + num2++ + } + } else { + if agent.GetColor() == 1 { + bnum1++ + } else { + bnum2++ + } + } + } + + if num1 > num2 { + vote1Ahead = true } else { - num2++ + vote1Ahead = false } } //if step == 0 { - fmt.Printf("%v,%v,%v\n", step, num1, num2) + fmt.Printf("%v,%v,%v,%v,%v, %v,%v\n", step, num1+bnum1, num2+bnum2, num1, num2, bnum1, bnum2) //} }