Monopoly Probe and Adjust
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
WHAT IS IT?
This model explores how a monopolist might discover the "monopoly quantity" (the quantity that maximizes profit for the monopolist agent) in the face of, here, a linear demand function.
Quantity is being adjusted and quantity is a continuous variable. This program uses what I call a "Probe and Adjust" model, and a very simple one at that. The agent begins with a current value, here currentQuantity, set by initialQuanity in the Interface tab. Play is organized by epochs, each containing a number of episodes. In each episode, the agent probes its market by offering a quantity in the range [currentQuantity - delta, currentQuantity + delta]. The agent records the revenue it gets form the probe, classifying the revenue as coming from a quantity offered that is either above or below the currentQuantity. When the epoch is over (a number of episodes, set by epochLength in the Interface tab), the agent determines whether on average it did better by offering more than the currentQuantity or less. Depending on the results, it increases its currentQuantity by epsilon or decreases it by epsilon. Then a new epoch begins. Both delta and epsilon are set in the Interface. The key point about this model is that the agent does not have access to the demand function, except as it responds to probing.
Introductory textbooks in microeconomics will tell the story roughly as follows. Suppose, for the sake of simplicity that the product in question can be produced at 0 cost. (Extensions of the model can be made for non-zero costs. The results will not be terribly sensitive to this.) The market's demand, Q (think: quantity demanded), for our product is a linear function of its price, P:
(1) Q(P) = Q = c - b*P
Here, c is a constant, representing the quantity demanded when price is 0 and, since we are linear, the price point at which demand disappears when the price is too high (when b*P = c). Rearranging (1) we get:
(2) P(Q) = P = a - dSlope*Q
where a = c/b and dSlope = 1/b. (We assume that dSlope > 0, so -dSlope < 0.)
The profit, pi, made by the monopolist is PQ (since the cost of production is 0, we need only account for revenue, which is defined here as PQ).
(3) pi = PQ = (a - dSlopeQ)Q = aQ - dSlopeQ*2
The monopolist will seek to maximize pi, which can be done by a simple exercise with the calculus.
(4) dpi/dQ = a - 2dSlopeQ
Setting a - 2dSlopeQ to zero and solving for Q yields
(5) Q = a/(2*dSlope)
So Q in (5) is Q*, the optimal quantity for the monopolist to put on the market.
(Checking that d2 pi/dQ2 = -2*dSlope < 0 verifies that we indeed have found a maximum.)
See, for example, IntermediateMicroeconomics:AModernApproach, 6th ed., by Hal. R. Varian. I draw explicitly on MicroeconomicTheory, 2nd ed., 1978, The Dryden Press, Hinsdale, Illinois, by Walter Nicholson. See "Appendix to Chapter 13: Models of Interdependent Output Decisions," pp. 389-398. Nicholson's is the more advanced text. My treatment generalizes his discussion. Kreps's _ACourseinMicroeconomicTheory, 1990, is excellent and more advanced.
HOW IT WORKS
The program variable slope corresponds to slope in equation (2). A slider on the Interface sets its value. The program variable qIBase (quantity-intercept, basic or initial) is the value of Q (quantity) at which P (price) equals 0. A slider on the Interface sets its value. See equation (2). So, a = dSlope*qIBase.
Put slightly differently, the demand function can be expressed as
Price(Quantity) = Price = priceIntercept - (dSlope * Quantity)
From the Interface tab we are given at initialization:
dSlope
and
qIBase
qIBase is the initial value of quantityIntercept. The program uses dSlope and qIBase to solve for priceIntercept, since:
0 = priceIntercept - (dSlope * quantityIntercept)
This gives us priceIntercept and dSlope, from which we can compute Price given a Quantity via the above equation, reproduced here:
Price(Quantity) = Price = priceIntercept - (dSlope * Quantity)
(Note on notation: Price and Quantity are variables, priceIntercept and dSlope are constants.)
Play is organized by epochs. There is a series of probes by the monopolist within each epoch, one probe per episode (market transaction). When the number of probes (episodes) is large enough (>= epochLength), the epoch concludes, adjustments are made, and a new epoch begins.
HOW TO USE IT
random-as is an On-Off switch. When it is off, the demand curve is set and fixed throughout the run, determined by q-i (initial quantity intercept) and slope. When random-as is on, then at the beginning of each probe (play) in an episode, quantity-intercept is randomly perturbed. There are two ways this might be done.
First, if the On-Off switch for random-walk-as is on, quantity-intercept is randomly reset uniformly between the current value of quantity-intercept plus a-delta and the current value of quantity-intercept minus a-delta. Second, if the On-Off switch for random-walk-as is off, quantity-intercept is randomly reset uniformly between the current value of q-i plus a-delta and the current value of q-i minus a-delta. In either case, the value for price-intercept is recalculated/reset, as are m-quantity and m-price.
RUNNING THE MODEL
On the Interface tab, click the setup button, then click the go button. The model will run until you click the go button again to stop it.
The Interface tab offers a number of sliders and switches for setting run parameter values.
initialQuantity
Sets the base, or anchor, quantity the monopolist agent uses during its first episode. As in all episodes, the agent has a base value for quantity and it probes by offering to the market quantities that are somewhat above or below this base quantity.
episodeLength
Sets the number of samples the monopolist agent takes before considering an adjustment of its base quantity value. The agent samples until the number of samples is greater than or equal to episodeLength. Then the agent adjusts its base quantity and a new episode begins.
daRandomSeed
Picking an item with this chooser determines how the random number generator is to be initialized for the run. Picking "system clock" lets NetLogo do the initialization. This will result in a different random number stream for each run. Picking a number results in the random number generated with that number, resulting in an identical random number stream for each run. This is useful for comparison and communication purposes. Also, note that the chooser is user-editable, so it it possible to add and delete entries.
random-as, random-walk-as
Price = a - dSlope*Quanity. dSlope is set by the interface slider:
dSlope
and a is the price intercept for the demand function (the value of the demand function when Quantity = 0. The initial value of the quantity intercept (the value of Quantity when Price = 0) is set with the Interface tab slider
qIBase
At initialization (in setup) qIBase is read into the program variable quantityIntercept.
aDelta
When random-as is on and random-walk-as is off, quantityIntercept is randomly changed each period by uniformly drawing in [quantityIntercept - aDelta, quantityIntercept + aDelta].
When both random-as is on and random-walk-as is on, quantityIntercept is randomly change each period as follows:
quantityIntercept(t+1) = U[-aDelta, aDelta] + quantityIntercept(t)
THINGS TO NOTICE
This section could give some ideas of things for the user to notice while running the model.
/* here, I need to say more */
THINGS TO TRY
Leave debug-switch off.
1) Simple example.
delta 3.0
epsilon 1.0
q-i 200
slope 2.0
fine-grained ON
initialQuantity 115.0
random-as Off
a-delta -
random-walk-as -
repeated-sampling Off
Quickly finds the static optimum quantity and bounces around, a little above and below. Experiment with reducing epsilon. Once the agent gets in the neighborhood of the static optimum, reduce epsilon, say to 0.1. The agent, of course, doesn't know the demand function. Is there a way the agent could sense that epsilon is too big (or too small)? Yes!
2) Random walk example
delta 3.0
epsilon 2.0
q-i 200
slope 2.0
fine-grained ON
initialQuantity 100
random-as On, random-seed 17
a-delta 0.9
random-walk-as On
repeated-sampling Off
EXTENDING THE MODEL
This section could give some ideas of things to add or change in the procedures tab to make the model more complicated, detailed, accurate, etc.
NETLOGO FEATURES
This section could point out any especially interesting or unusual features of NetLogo that the model makes use of, particularly in the Procedures tab. It might also point out places where workarounds were needed because of missing features.
RELATED MODELS
This section could give the names of models in the NetLogo Models Library or elsewhere which are of related interest.
CREDITS AND REFERENCES
This model was created and written by Steven O. Kimbrough: kimbrough at wharton.upenn.edu and http://opim-sky.wharton.upenn.edu/~sok/. The model is
freely downloadable at:
http://opim-sky.wharton.upenn.edu/~sok/agebook/applications/nlogo/monopolyProbeAndAdjust.nlogo
Please give me credit if you use this model or program.
To refer to this model in academic publications, please use: Kimbrough, Steven O. (2007). Monopoly Probe and Adjust
model. http://opim-sky.wharton.upenn.edu/~sok/agebook/applications/nlogo/monopolyProbeAndAdjust.nlogo University of Pennsylvania, Philadelphia, PA 19004, USA.
In other publications, please use: Copyright 2007 Steven O. Kimbrough. All
rights reserved.
$Id: MonopolyProbeAndAdjust.nlogo 4082 2014-03-20 00:40:40Z sok $
Comments and Questions
globals [pstar current-price price-intercept m-price epochOver up-data down-data total-revenue probe-count ;episodeLength quantityIntercept up-prices down-prices ;monop-prices monop-quantities m-up-prices m-dn-prices m-up-revs m-dn-revs up-as down-as currentQuantity m-quantity initial-m-quantity initial-m-price initial-price version ; CVS (or Subversion) version string ] to setup set version "$Id: MonopolyProbeAndAdjust.nlogo 4082 2014-03-20 00:40:40Z sok $" if (daRandomSeed != "system clock") [random-seed daRandomSeed] set quantityIntercept qIBase set currentQuantity initialQuantity set price-intercept daPriceIntercept(quantityIntercept)(dSlope) set current-price (price-intercept - (dSlope * initialQuantity)) set initial-price current-price set m-quantity daMQuantity ; (price-intercept / ( 2 * slope)) ; set the monopoly quantity set initial-m-quantity m-quantity set initial-m-price (price-intercept - (dSlope * initial-m-quantity)) set m-price getMPrice(price-intercept)(dSlope)(m-quantity) clear-all-plots plot-quantity-price(current-price) set epochOver false set up-data [] set up-prices [] set down-data [] set down-prices [] set monop-quantities [] set m-up-prices [] set m-dn-prices [] set m-up-revs [] set m-dn-revs [] set up-as [] set down-as [] set total-revenue 0 set probe-count 0 end to go let probe 0 let myRevenue 0 while [not epochOver] [ ; If random-as, that is if a in the demand function, = a + b*p, is to be be set ; via random walk, then ; figure out the new demand curve. if (random-as) [ ifelse (random-walk-as) [set quantityIntercept (random-float 2 * aDelta) - aDelta + quantityIntercept] [set quantityIntercept (random-float 2 * aDelta) - aDelta + qIBase] ;quantityIntercept set price-intercept daPriceIntercept(quantityIntercept)(dSlope) ; quantityIntercept * slope set m-quantity daMQuantity ; quantityIntercept / (2 * slope) set m-price getMPrice(price-intercept)(dSlope)(m-quantity) ] ; end of if (random-as) ; repeated-sampling. If On, our new probe is currentQuantity plus or minus delta. ; If Off, our new probe ranges uniformly between currentQuantity plus and minus delta. ifelse (repeated-sampling) [set probe (random-float 1) ifelse (probe <= 0.5) [set probe currentQuantity - delta] [set probe currentQuantity + delta]] ; end of if in ifelse(repeated-sampling) [set probe (random-float 2 * delta) - delta + currentQuantity] ; end of ifelse repeated-sampling set current-price (price-intercept - (dSlope * probe)) set probe-count probe-count + 1 set myRevenue daRevenue(probe) set total-revenue total-revenue + myRevenue ; daRevenue(probe) ifelse (probe >= currentQuantity) [set up-data lput myRevenue up-data] [set down-data lput myRevenue down-data] if (fine-grained) [plot-quantities(currentQuantity)(m-quantity)] ; if (length up-data > episodeLength and length down-data > episodeLength) if (length up-data + length down-data >= epochLength) [set epochOver true] ] ; end of do while if (epochOver) [ifelse (mean up-data >= mean down-data) [set currentQuantity (currentQuantity + epsilon)] [set currentQuantity (currentQuantity - epsilon)] if (not fine-grained) [plot-quantities(currentQuantity)(m-quantity)] set epochOver false set up-data [] set down-data [] ] ; end of if(epochOver) end to plot-quantity-price [daPrice] set-current-plot "quantity-price" clear-plot set-plot-y-range 0 price-intercept set-plot-x-range 0 quantityIntercept set-current-plot-pen "Demand Curve" plot-pen-up plotxy 0 price-intercept plot-pen-down plotxy quantityIntercept 0 set-current-plot-pen "Monopoly Quantity" plot-pen-up plotxy m-quantity 0 plot-pen-down plotxy m-quantity m-price set-current-plot-pen "Monopoly Price" plot-pen-up plotxy 0 m-price plot-pen-down plotxy m-quantity m-price end to-report daRevenue [daQuantity] ; [daPrice] let daPrice 0 set daPrice (price-intercept - (dSlope * daQuantity)) report daPrice * daQuantity end to-report daPriceIntercept [q-intercept daSlope] set price-intercept (q-intercept * daSlope) report price-intercept end to-report daMQuantity set m-quantity (price-intercept / ( 2 * dSlope)) report m-quantity end to-report getMPrice [da-price-intercept da-slope da-m-quantity] report (da-price-intercept - (da-slope * da-m-quantity)) end to plot-quantities [daQuantity mono-quant] set-current-plot "Monopoly and Current Quantities" set-current-plot-pen "Agent's Quantity" plot daQuantity set-current-plot-pen "Monopoly Quantity" plot mono-quant end to debug let probe 0 if (random-as) [ set quantityIntercept (random-float 2 * aDelta) - aDelta + qIBase ;quantityIntercept set price-intercept quantityIntercept / dSlope set m-price quantityIntercept / (2 * dSlope) ;set monop-prices lput m-price monop-prices ] ; if of if (random-as) set probe (random-float 2 * delta) - delta + current-price show (word "a = " quantityIntercept) show (word "price intercept = " price-intercept) show (word "dSlope = " dSlope) show (word "monopoly price = " m-price) show (word "monopoly demand = " (quantityIntercept - dSlope * m-price) ) show (word "monopoly revenue = " daRevenue(m-price) ) show (word "current-price = " current-price) show (word "probe = " probe) show (word "probe revenue = " daRevenue(probe)) end
There is only one version of this model, created over 8 years ago by Steven Kimbrough.
Attached files
No files
This model does not have any ancestors.
This model does not have any descendants.