我根据维基百科文章中的描述进行了模拟。我没有看到 N 节点的 N^2 冲突附近的任何地方,每个节点都尝试在第一个时间帧发送一次,并且一旦它们的单个消息在没有冲突的情况下传输,就再也不会再次传输。
Nodes Coll Lost Succ Frames
0 0.0 0.0 0.0 0.0
1 0.0 0.0 1.0 1.0
2 1.655 3.31 2.0 5.334
3 2.623 6.546 3.0 9.238
4 3.764 10.698 4.0 14.327
5 4.787 15.01 5.0 19.417
6 5.944 19.869 6.0 25.821
7 6.911 24.718 7.0 31.432
8 8.033 30.155 8.0 38.464
9 9.11 35.591 9.0 44.295
10 10.165 41.137 10.0 51.748
11 11.263 47.043 11.0 58.642
12 12.395 53.029 12.0 66.874
13 13.434 59.097 13.0 75.109
14 14.449 65.097 14.0 81.917
15 15.443 71.27 15.0 88.52
16 16.453 77.544 16.0 97.961
17 17.483 84.04 17.0 104.177
18 18.711 90.877 18.0 116.288
19 19.539 97.185 19.0 120.451
20 20.67 104.059 20.0 130.952
21 21.592 110.561 21.0 140.519
22 22.691 117.556 22.0 146.973
23 23.832 124.608 23.0 158.805
24 24.667 131.162 24.0 163.776
25 25.85 138.41 25.0 176.745
26 26.92 145.641 26.0 189.071
27 27.823 152.719 27.0 197.514
28 28.942 160.104 28.0 207.642
29 29.875 166.963 29.0 215.736
30 30.866 174.161 30.0 225.025
31 31.686 181.132 31.0 229.19
32 32.947 189.118 32.0 242.804
33 33.973 196.505 33.0 252.973
34 34.948 203.764 34.0 263.166
35 36.192 212.065 35.0 273.805
36 36.795 218.552 36.0 277.656
37 37.966 226.543 37.0 292.611
38 39.197 234.595 38.0 307.013
39 39.908 241.305 39.0 309.537
40 41.057 249.609 40.0 323.217
41 42.183 257.519 41.0 331.323
42 43.223 265.094 42.0 344.867
43 43.981 272.823 43.0 349.558
44 44.934 280.297 44.0 355.776
45 46.106 288.5 45.0 375.085
46 47.277 296.807 46.0 384.67
47 48.397 304.742 47.0 401.301
48 49.207 312.141 48.0 412.576
49 50.146 320.155 49.0 417.144
这些是发生冲突的平均帧数、冲突中涉及的传输尝试次数、成功传输的次数(每个节点应该是一个)以及每个节点传输所需的帧数成功地。
这是我在 Haskell 中进行的模拟
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, DeriveFunctor, OverlappingInstances #-}
-- OverlapingInstances shouldn't be required; there's no Functor instance for NodeDict.
module Main (
main
) where
import System.Random
import qualified Data.Foldable as Foldable
main = do
output ["Nodes", "Coll", "Lost", "Succ", "Frames"]
sequence_ $ map expirement $ take 50 $ iterate (1+) 0
expirement n = do
let numTrials = 1000
results <- sequence $ take numTrials $ repeat (trial n)
let averages = summarize average results
output [show n, show $ collisions averages, show $ lostTransmissions averages, show $ successfulTransmissions averages, show $ frames averages ]
trial n = do
generator <- newStdGen
let network = take n $ randomNodes generator
let monitoredNetwork = (Passive $ Monitor [], network)
let (Passive (Monitor result), _) = simulate monitoredNetwork
return TrialResult {
collisions = count collision result,
lostTransmissions = sum $ map collided $ filter collision result,
successfulTransmissions = count (==Frame) result,
frames = length result
}
-- Initialize network with exponential backoffs
randomNodes :: (RandomGen g) => g -> [Single (NodeDict Transmission Reception)]
randomNodes = map randomNode . splits
where
randomNode generator = Single $ backOffTransmissions (randomExponentialBackoffSchedules generator) $ transmit done
data TrialResult a = TrialResult {
collisions :: !a,
lostTransmissions :: !a,
successfulTransmissions :: !a,
frames :: !a
} deriving Show
average :: (Real r, Fractional a) => [r] -> a
average results = (fromRational . toRational $ sum results) / (fromRational $ toRational $ length results)
summarize :: ([a] -> b) -> [TrialResult a] -> TrialResult b
summarize summarizer results = TrialResult {
collisions = summarizer $ map collisions results,
lostTransmissions = summarizer $ map lostTransmissions results,
successfulTransmissions = summarizer $ map successfulTransmissions results,
frames = summarizer $ map frames results
}
output = putStrLn . concat . map (padr 8)
padr :: Int -> [Char] -> [Char]
padr n s = take n $ s ++ repeat ' '
-- Model for nodes
class Transmitter t s where
transmission :: s -> t
class Reciever r s where
recieve :: r -> s -> s
-- Ordinary node with no type information attached
data NodeDict t r = NodeDict {
_transmission :: t,
_recieve :: r -> NodeDict t r
}
instance Transmitter t (NodeDict t r) where
transmission = _transmission
instance Reciever r (NodeDict t r) where
recieve = flip _recieve
-- Networks
class Transmitters t s where
transmissions :: s -> [t]
-- Network consisting of a single node
newtype Single a = Single {
only :: a
} deriving Functor
instance Transmitter t s => Transmitters t (Single s) where
transmissions = (replicate 1) . transmission . only
-- Network instance for a list of networks
instance (Transmitters t s, Foldable.Foldable f) => Transmitters t (f s) where
transmissions = Foldable.foldMap transmissions
instance (Reciever r s, Functor f) => Reciever r (f s) where
recieve r = fmap (recieve r)
-- Network instances for tuples of networks
instance (Transmitters t sa, Transmitters t sb) => Transmitters t (sa, sb) where
transmissions (a, b) = transmissions a ++ transmissions b
instance (Reciever r sa, Reciever r sb) => Reciever r (sa, sb) where
recieve r (a, b) = (recieve r a, recieve r b)
-- Node that monitors the network
newtype Passive a = Passive {
unPassive :: a
} deriving Functor
instance Transmitters t (Passive a) where
transmissions _ = []
newtype Monitor a = Monitor {
observations :: [a]
}
instance Reciever r (Monitor r) where
recieve r s = Monitor (r:observations s)
-- Our signals
data Transmission = Done | Waiting | Transmitting deriving (Show, Eq)
data Reception = None | Frame | Collision {collided :: Int} deriving (Show, Eq)
collision :: Reception -> Bool
collision (Collision _) = True
collision _ = False
-- Simulate collisions in a network
count :: (a -> Bool) -> [a] -> Int
count f = length . filter f
simulate :: (Transmitters Transmission s, Reciever Reception s) => s -> s
simulate state =
case all (==Done) current of
False ->
simulate nextState
where
currentlyTransmitting = count (==Transmitting) current
signal =
case currentlyTransmitting of
0 -> None
1 -> Frame
_ -> Collision currentlyTransmitting
nextState = recieve signal state
_ -> state
where current = transmissions state
-- Some network nodes
-- Node that does something, ignores what it recieves and does the next thing
node :: t -> NodeDict t r -> NodeDict t r
node t r = NodeDict {
_transmission = t,
_recieve = \_ -> r
}
-- Done forever
done :: NodeDict Transmission r
done = node Done done
-- Wait, then do the next thing
wait :: NodeDict Transmission r -> NodeDict Transmission r
wait = node Waiting
-- Transmit, then do the next thing
transmit :: NodeDict Transmission r -> NodeDict Transmission r
transmit = node Transmitting
-- When transmitting, check for collision and back off acording to the current schedule
backOffTransmissions :: [[Int]] -> NodeDict Transmission Reception -> NodeDict Transmission Reception
backOffTransmissions schedules n = NodeDict {
_transmission = (transmission n),
_recieve = case (transmission n==Transmitting) of
True -> \r -> case (collision r) of
True -> (iterate wait $ backOffTransmissions newSchedules n) !! steps
where
((steps: thisSchedule) : remainingSchedules) = schedules
newSchedules = thisSchedule : remainingSchedules
False -> backOffTransmissions (tail schedules) (recieve r n)
_ -> \r -> backOffTransmissions schedules (recieve r n)
}
-- Exponential backoff
powersOf2 :: Num n => [n]
powersOf2 = iterate (*2) 1
exponentialBackoffRanges :: Num n => [(n,n)]
exponentialBackoffRanges = map (\x -> (0, x-1)) $ tail powersOf2
exponentialBackoffGenerators :: (Num n, Random n, RandomGen g) => [g -> (n, g)]
exponentialBackoffGenerators = map randomR exponentialBackoffRanges
zipRandom :: RandomGen g => [g -> (a, g)] -> g -> [a]
zipRandom (step:steps) generator =
let (value, nextGenerator) = step generator
in value : zipRandom steps nextGenerator
splits :: RandomGen g => g -> [g]
splits = zipRandom (repeat split)
randomExponentialBackoffs :: (RandomGen g, Random n, Num n) => g -> [n]
randomExponentialBackoffs = zipRandom exponentialBackoffGenerators
randomExponentialBackoffSchedules :: (RandomGen g, Random n, Num n) => g -> [[n]]
randomExponentialBackoffSchedules = map randomExponentialBackoffs . splits
编辑以包含更多统计数据以与其他模拟进行比较