diff --git a/config.yaml b/config.yaml index 0d93be9..ba114f1 100644 --- a/config.yaml +++ b/config.yaml @@ -55,7 +55,7 @@ BaseOptions: MeanRewardPerForward: false AverageNumberOfHops: false HopFractionOfTotalRewards: false - NegaticeIncome: false + NegativeIncome: false IncomeGini: true IncomeTheil: false HopIncome: false diff --git a/config/config_types.go b/config/config_types.go index 57c83ce..b88cc0a 100644 --- a/config/config_types.go +++ b/config/config_types.go @@ -54,7 +54,9 @@ type experimentOptions struct { CacheIsEnabled bool `yaml:"CacheIsEnabled"` PreferredChunks bool `yaml:"PreferredChunks"` AdjustableThreshold bool `yaml:"AdjustableThreshold"` + VariableRefreshrate bool `yaml:"VariableRefreshrate"` PayIfOrigPays bool `yaml:"PayIfOrigPays"` + RouteOnlyNearest bool `yaml:"RouteOnlyNearest"` } type outputOptions struct { diff --git a/config/default_variables.go b/config/default_variables.go index 13c0b21..c5092eb 100644 --- a/config/default_variables.go +++ b/config/default_variables.go @@ -65,6 +65,8 @@ func getDefaultConfig() Config { CacheIsEnabled: false, // false PreferredChunks: false, // false AdjustableThreshold: false, // false + VariableRefreshrate: false, // false + RouteOnlyNearest: false, // false }, } } diff --git a/config/get_variables.go b/config/get_variables.go index 8c6cd5a..f4c7281 100644 --- a/config/get_variables.go +++ b/config/get_variables.go @@ -31,6 +31,10 @@ func IsAdjustableThreshold() bool { return theconfig.ExperimentOptions.AdjustableThreshold } +func IsVariableRefreshrate() bool { + return theconfig.ExperimentOptions.VariableRefreshrate +} + func GetAdjustableThresholdExponent() int { return theconfig.BaseOptions.AdjustableThresholdExponent } @@ -71,6 +75,10 @@ func IsPayIfOrigPays() bool { return theconfig.ExperimentOptions.PayIfOrigPays } +func IsRouteOnlyNearest() bool { + return theconfig.ExperimentOptions.RouteOnlyNearest +} + func IsPayOnlyForCurrentRequest() bool { return theconfig.ExperimentOptions.PayOnlyForCurrentRequest } @@ -322,6 +330,12 @@ func GetExperimentString() (exp string) { if IsAdjustableThreshold() { exp += "FgAdj" } + if !IsPayOnlyForCurrentRequest() { + exp += "FullDept" + } + if IsRouteOnlyNearest() { + exp += "Nearest" + } exp += "-" + GetExpeimentId() return exp diff --git a/config/init_configs.go b/config/init_configs.go index ceb98a7..b40ce9a 100644 --- a/config/init_configs.go +++ b/config/init_configs.go @@ -14,8 +14,8 @@ import ( // theconfig This is the current configuration. var theconfig Config -func InitConfig() { - config, err := ReadYamlFile("config.yaml") +func InitConfig(configfile string) { + config, err := ReadYamlFile(configfile) if err != nil { log.Panicln("Unable to read config file: config.yaml") } diff --git a/generate_network_data/README.md b/generate_network_data/README.md new file mode 100644 index 0000000..ed0f3d7 --- /dev/null +++ b/generate_network_data/README.md @@ -0,0 +1,7 @@ +To generate a network with the second choice option, you need to use the `config` parameter. +E.g. +```bash +cd generate_network_data +go build +./generate_network_data -random=false -config=true -conffile=../config.yaml +``` \ No newline at end of file diff --git a/generate_network_data/generate_data.go b/generate_network_data/generate_data.go index b1edb17..d97d8de 100644 --- a/generate_network_data/generate_data.go +++ b/generate_network_data/generate_data.go @@ -21,11 +21,12 @@ func main() { count := flag.Int("count", -1, "generate count many networks with ids i0,i1,...") random := flag.Bool("random", true, "spread nodes randomly") useconfig := flag.Bool("config", false, "use config.yaml to initialize bits, binSize, NetworkSize and randomness") + conffile := flag.String("conffile", "config.yaml", "specify config file") flag.Parse() if *useconfig { - config.InitConfig() + config.InitConfig(*conffile) *binSize = config.GetBinSize() *bits = config.GetBits() *networkSize = config.GetNetworkSize() diff --git a/main.go b/main.go index a9e2e31..eb5ec52 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ import ( ) func main() { + configfile := flag.String("conf", "config.yaml", "path to config file to use") graphId := flag.String("graphId", "", "an Id for the graph, e.g. even") count := flag.Int("count", -1, "run for different networks with ids i0,i1,...") maxPOs := flag.String("maxPOs", "", "min:max maxPO value") @@ -46,18 +47,18 @@ func main() { for maxPO := min; maxPO < max; maxPO++ { if *count < 0 { - run(-1, *graphId, maxPO) + run(-1, *graphId, maxPO, *configfile) } for i := 0; i < *count; i++ { - run(i, *graphId, maxPO) + run(i, *graphId, maxPO, *configfile) } } } -func run(iteration int, graphId string, maxPO int) { +func run(iteration int, graphId string, maxPO int, configfile string) { start := time.Now() - config.InitConfig() + config.InitConfig(configfile) if maxPO > -1 { config.SetMaxPO(maxPO) } diff --git a/model/parts/types/graph.go b/model/parts/types/graph.go index 9f5b72b..d366980 100644 --- a/model/parts/types/graph.go +++ b/model/parts/types/graph.go @@ -2,7 +2,9 @@ package types import ( "fmt" + "go-incentive-simulation/config" "go-incentive-simulation/model/general" + "math" "sync" ) @@ -11,7 +13,7 @@ type Graph struct { *Network CurState State Edges map[NodeId]map[NodeId]*Edge - rwMutex sync.RWMutex + rwMutex sync.RWMutex } // Edge that connects to NodesMap with attributes about the connection @@ -27,9 +29,10 @@ type Edge struct { // "lastEpoch" is the epoch where it was last forgiven. // "threshold" is for the adjustable threshold limit. type EdgeAttrs struct { - A2B int - LastEpoch int - Threshold int + A2B int + LastEpoch int + Threshold int + Refreshrate int } func (g *Graph) GetNodeAdj(nodeId NodeId) [][]NodeId { @@ -43,7 +46,7 @@ func (g *Graph) GetNodeAdj(nodeId NodeId) [][]NodeId { } // AddEdge will add an edge from a node to a node -func (g *Graph) AddEdge(fromNodeId NodeId, toNodeId NodeId, attrs EdgeAttrs) error { +func (g *Graph) AddEdge(fromNodeId NodeId, toNodeId NodeId) error { toNode := g.NodesMap[toNodeId] fromNode := g.NodesMap[fromNodeId] if toNode == nil || fromNode == nil { @@ -55,12 +58,37 @@ func (g *Graph) AddEdge(fromNodeId NodeId, toNodeId NodeId, attrs EdgeAttrs) err if g.unsafeEdgeExists(toNodeId, fromNodeId) { mutex = g.Edges[toNodeId][fromNodeId].Mutex } - newEdge := &Edge{FromNodeId: fromNodeId, ToNodeId: toNodeId, Attrs: attrs, Mutex: mutex} + newEdge := &Edge{FromNodeId: fromNodeId, ToNodeId: toNodeId, Attrs: EdgeAttrs{}, Mutex: mutex} + newEdge.InitThresholdAndRefreshrate() g.Edges[fromNodeId][toNodeId] = newEdge return nil } } +func (e *Edge) InitThresholdAndRefreshrate() { + threshold := config.GetThreshold() + refreshrate := config.GetRefreshRate() + if config.IsVariableRefreshrate() { + threshold = config.GetMaxProximityOrder() + } + + if config.IsAdjustableThreshold() { + threshold = threshold - config.GetBits() + general.BitLength(e.FromNodeId.ToInt()^e.ToNodeId.ToInt()) + if threshold < 0 { + threshold = 0 + } + refreshrate = GetAdjustedRefreshrate(threshold, config.GetThreshold(), config.GetRefreshRate(), config.GetAdjustableThresholdExponent()) + } + + e.Attrs.Threshold = threshold + e.Attrs.Refreshrate = refreshrate +} + +func GetAdjustedRefreshrate(adjustedThreshold, threshold, refreshRate, power int) int { + ratio := float64(adjustedThreshold) / float64(threshold) + return int(math.Ceil(float64(refreshRate) * math.Pow(ratio, float64(power)))) +} + func (g *Graph) NewNode() (*Node, error) { g.rwMutex.Lock() node := g.Network.NewNode() @@ -71,13 +99,11 @@ func (g *Graph) NewNode() (*Node, error) { nodeAdj := node.AdjIds for _, adjItems := range nodeAdj { for _, otherNodeId := range adjItems { - threshold := general.BitLength(node.Id.ToInt() ^ otherNodeId.ToInt()) - attrs := EdgeAttrs{A2B: 0, LastEpoch: 0, Threshold: threshold} - err := g.AddEdge(node.Id, otherNodeId, attrs) + err := g.AddEdge(node.Id, otherNodeId) if err != nil { return nil, err } - err = g.AddEdge(otherNodeId, node.Id, attrs) + err = g.AddEdge(otherNodeId, node.Id) if err != nil { return nil, err } @@ -116,7 +142,7 @@ func (g *Graph) GetEdge(fromNodeId NodeId, toNodeId NodeId) *Edge { g.rwMutex.Lock() defer g.rwMutex.Unlock() - err := g.AddEdge(fromNodeId, toNodeId, EdgeAttrs{}) + err := g.AddEdge(fromNodeId, toNodeId) if err != nil { return nil } @@ -147,6 +173,38 @@ func (g *Graph) unsafeEdgeExists(fromNodeId NodeId, toNodeId NodeId) bool { return false } +func (g *Graph) SetEdgeA2B(fromNodeId NodeId, toNodeId NodeId, a2b int) bool { + if g.EdgeExists(fromNodeId, toNodeId) { + g.Edges[fromNodeId][toNodeId].Attrs.A2B = a2b + return true + } + return false +} + +func (g *Graph) SetEdgeIncrementThreshold(fromNodeId NodeId, toNodeId NodeId) bool { + if g.EdgeExists(fromNodeId, toNodeId) { + threshold := g.Edges[fromNodeId][toNodeId].Attrs.Threshold + if threshold < config.GetThreshold() { + g.Edges[fromNodeId][toNodeId].Attrs.Threshold++ + } + if g.Edges[fromNodeId][toNodeId].Attrs.Refreshrate < config.GetThreshold()/2 { + g.Edges[fromNodeId][toNodeId].Attrs.Refreshrate++ + } + return true + } + return false +} + +func (g *Graph) SetEdgeDecrementThreshold(fromNodeId NodeId, toNodeId NodeId) bool { + if g.EdgeExists(fromNodeId, toNodeId) { + if g.Edges[fromNodeId][toNodeId].Attrs.Refreshrate > config.GetRefreshRate() { + g.Edges[fromNodeId][toNodeId].Attrs.Refreshrate-- + } + return true + } + return false +} + func (g *Graph) SetEdgeData(fromNodeId NodeId, toNodeId NodeId, edgeAttrs EdgeAttrs) bool { if g.EdgeExists(fromNodeId, toNodeId) { g.Edges[fromNodeId][toNodeId].Attrs = edgeAttrs diff --git a/model/parts/types/network.go b/model/parts/types/network.go index ae9b9c6..f578124 100644 --- a/model/parts/types/network.go +++ b/model/parts/types/network.go @@ -3,6 +3,8 @@ package types import ( "encoding/json" "fmt" + "go-incentive-simulation/config" + "go-incentive-simulation/model/general" "math/rand" "os" "sync" @@ -119,10 +121,10 @@ func (network *Network) node(nodeId NodeId) *Node { panic("address out of range") } res := Node{ - Network: network, - Id: nodeId, - AdjIds: make([][]NodeId, network.Bits), - Active: true, + Network: network, + Id: nodeId, + AdjIds: make([][]NodeId, network.Bits), + Active: true, OriginatorStruct: OriginatorStruct{ RequestCount: 0, }, @@ -162,8 +164,14 @@ func (network *Network) node(nodeId NodeId) *Node { func (network *Network) Generate(count int, random bool) []*Node { nodeIds := generateIds(count, (1< 0 { + fmt.Println("second choice!") + nodeIds = generateIdsSecondChoice(count, (1<= config.GetStorageDepth() +} + +func generateIdsSecondChoice(totalNumbers int, maxValue int) []int { + generatedNumbers := make(map[int]bool) + for len(generatedNumbers) < totalNumbers { + num1 := rand.Intn(maxValue-1) + 1 + for generatedNumbers[num1] == true { + num1 = rand.Intn(maxValue-1) + 1 + } + num2 := rand.Intn(maxValue-1) + 1 + for generatedNumbers[num2] == true { + num2 = rand.Intn(maxValue-1) + 1 + } + cnt1, cnt2 := 0, 0 + for num := range generatedNumbers { + if isneighbor(num1, num) { + cnt1++ + } + if isneighbor(num2, num) { + cnt2++ + } + } + if cnt1 <= cnt2 { + generatedNumbers[num1] = true + } else { + generatedNumbers[num2] = true + } + } + + result := make([]int, 0, totalNumbers) + for num := range generatedNumbers { + result = append(result, num) + } + return result +} + func generateIdsEven(totalNumbers int, maxValue int) []int { result := make([]int, 0, totalNumbers) step := float64(maxValue) / float64(totalNumbers) @@ -252,4 +298,3 @@ func generateIdsEven(totalNumbers int, maxValue int) []int { } return result[:totalNumbers] } - diff --git a/model/parts/update/update_graph.go b/model/parts/update/update_graph.go index 4dcd587..a4f2730 100644 --- a/model/parts/update/update_graph.go +++ b/model/parts/update/update_graph.go @@ -27,22 +27,17 @@ func Graph(state *types.State, requestResult types.RequestResult, curTimeStep in } if actualPrice < 0 { continue + } + if !config.IsPayOnlyForCurrentRequest() { + state.Graph.SetEdgeA2B(payment.FirstNodeId, payment.PayNextId, 0) + state.Graph.SetEdgeA2B(payment.PayNextId, payment.FirstNodeId, 0) } else { - if !config.IsPayOnlyForCurrentRequest() { - newEdgeData1 := edgeData1 - newEdgeData1.A2B = 0 - state.Graph.SetEdgeData(payment.FirstNodeId, payment.PayNextId, newEdgeData1) - - newEdgeData2 := edgeData2 - newEdgeData2.A2B = 0 - state.Graph.SetEdgeData(payment.PayNextId, payment.FirstNodeId, newEdgeData2) - } else { - // Important fix: Reduce debt here, since it debt will be added again below. - // Idea is, paying for the current request should not effect the edge balance. - newEdgeData1 := edgeData1 - newEdgeData1.A2B = edgeData1.A2B - price - state.Graph.SetEdgeData(payment.FirstNodeId, payment.PayNextId, newEdgeData1) - } + // Important fix: Reduce debt here, since it debt will be added again below. + // Idea is, paying for the current request should not effect the edge balance. + state.Graph.SetEdgeA2B(payment.FirstNodeId, payment.PayNextId, edgeData1.A2B-price) + } + if config.IsVariableRefreshrate() { + state.Graph.SetEdgeIncrementThreshold(payment.FirstNodeId, payment.PayNextId) } // fmt.Println("Payment from ", payment.FirstNodeId, " to ", payment.PayNextId, " for chunk ", payment.ChunkId, " with price ", actualPrice) paymentWithPrice = types.PaymentWithPrice{Payment: payment, Price: actualPrice} @@ -58,9 +53,7 @@ func Graph(state *types.State, requestResult types.RequestResult, curTimeStep in providerNode := route[i+1] price := utils.PeerPriceChunk(providerNode, chunkId) edgeData := state.Graph.GetEdgeData(requesterNode, providerNode) - newEdgeData := edgeData - newEdgeData.A2B += price - state.Graph.SetEdgeData(requesterNode, providerNode, newEdgeData) + state.Graph.SetEdgeA2B(requesterNode, providerNode, edgeData.A2B+price) if config.GetMaxPOCheckEnabled() { nodePairWithPrice = types.NodePairWithPrice{RequesterNode: requesterNode, ProviderNode: providerNode, Price: price} diff --git a/model/parts/utils/utils.go b/model/parts/utils/utils.go index 247b4e2..4449490 100644 --- a/model/parts/utils/utils.go +++ b/model/parts/utils/utils.go @@ -41,9 +41,7 @@ func CreateGraphNetwork(net *types.Network) (*types.Graph, error) { nodeAdj := node.AdjIds for _, adjItems := range nodeAdj { for _, otherNodeId := range adjItems { - threshold := general.BitLength(nodeId.ToInt() ^ otherNodeId.ToInt()) - attrs := types.EdgeAttrs{A2B: 0, LastEpoch: 0, Threshold: threshold} - err := graph.AddEdge(node.Id, otherNodeId, attrs) + err := graph.AddEdge(node.Id, otherNodeId) if err != nil { return nil, err } diff --git a/model/routing/forgiveness.go b/model/routing/forgiveness.go index 5dd1a61..11c554d 100644 --- a/model/routing/forgiveness.go +++ b/model/routing/forgiveness.go @@ -3,7 +3,6 @@ package routing import ( "go-incentive-simulation/config" "go-incentive-simulation/model/parts/types" - "math" ) func CheckForgiveness(edgeData types.EdgeAttrs, firstNodeId types.NodeId, secondNodeId types.NodeId, graph *types.Graph, request types.Request) (int, bool) { @@ -13,10 +12,7 @@ func CheckForgiveness(edgeData types.EdgeAttrs, firstNodeId types.NodeId, second return edgeData.A2B, false } - refreshRate := config.GetRefreshRate() - if config.IsAdjustableThreshold() { - refreshRate = GetAdjustedRefreshrate(edgeData.Threshold, config.GetThreshold(), config.GetRefreshRate(), config.GetAdjustableThresholdExponent()) - } + refreshRate := edgeData.Refreshrate removedDeptAmount := passedTime * refreshRate newEdgeData := edgeData @@ -26,11 +22,9 @@ func CheckForgiveness(edgeData types.EdgeAttrs, firstNodeId types.NodeId, second } newEdgeData.LastEpoch = request.Epoch graph.SetEdgeData(firstNodeId, secondNodeId, newEdgeData) + if config.IsVariableRefreshrate() { + graph.SetEdgeDecrementThreshold(firstNodeId, secondNodeId) + } return newEdgeData.A2B, true } - -func GetAdjustedRefreshrate(adjustedThreshold, threshold, refreshRate, power int) int { - ratio := float64(adjustedThreshold) / float64(threshold) - return int(math.Ceil(float64(refreshRate) * math.Pow(ratio, float64(power)))) -} diff --git a/model/routing/routing.go b/model/routing/routing.go index 89833fe..4b0c2c0 100644 --- a/model/routing/routing.go +++ b/model/routing/routing.go @@ -65,10 +65,11 @@ func getNext(request types.Request, firstNodeId types.NodeId, prevNodePaid bool, // found new nextNode, release lock on previous found. graph.UnlockEdge(firstNodeId, nextNodeId) } - if !payNextId.IsNil() { + if !payNextId.IsNil() && dist <= payDist { // found new nextNode, without payment, release lock on previous found payNext. graph.UnlockEdge(firstNodeId, payNextId) payNextId = -1 // IMPORTANT! + payDist = dist } } @@ -78,16 +79,18 @@ func getNext(request types.Request, firstNodeId types.NodeId, prevNodePaid bool, thresholdFailed = true if config.GetPaymentEnabled() { - if dist < payDist && nextNodeId.IsNil() { + if dist < payDist { if config.IsEdgeLock() && !payNextId.IsNil() { graph.UnlockEdge(firstNodeId, payNextId) } payDist = dist payNextId = nodeId } else if config.IsEdgeLock() { + // not free, and not a better payment option, release. graph.UnlockEdge(firstNodeId, nodeId) } } else if config.IsEdgeLock() { + // not free and no payment enabled, release graph.UnlockEdge(firstNodeId, nodeId) } } @@ -100,6 +103,21 @@ func getNext(request types.Request, firstNodeId types.NodeId, prevNodePaid bool, accessFailed = true } + if !nextNodeId.IsNil() && !payNextId.IsNil() { + // found a free peer, and a peer with payment, but closer + if config.IsRouteOnlyNearest() { + if config.IsEdgeLock() { + graph.UnlockEdge(firstNodeId, nextNodeId) + } + nextNodeId = -1 + } else { + if config.IsEdgeLock() { + graph.UnlockEdge(firstNodeId, payNextId) + } + payNextId = -1 + } + } + if config.GetPaymentEnabled() && !payNextId.IsNil() { accessFailed = false diff --git a/model/routing/threshold.go b/model/routing/threshold.go index 1d175ba..8ce836a 100644 --- a/model/routing/threshold.go +++ b/model/routing/threshold.go @@ -16,10 +16,7 @@ func IsThresholdFailed(firstNodeId types.NodeId, secondNodeId types.NodeId, grap edgeDataSecond := graph.GetEdgeData(secondNodeId, firstNodeId) p2pSecond := edgeDataSecond.A2B - threshold := config.GetThreshold() - if config.IsAdjustableThreshold() { - threshold = edgeDataFirst.Threshold - } + threshold := edgeDataFirst.Threshold peerPriceChunk := utils.PeerPriceChunk(secondNodeId, request.ChunkId)