Monopoly Probe and Adjust

No preview image

1 collaborator

Default-person Steven Kimbrough (Author)


"probe and adjust" 

Tagged by Steven Kimbrough about 8 years ago


Tagged by Steven Kimbrough about 8 years ago


Tagged by Steven Kimbrough about 8 years ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 5.0.3 • Viewed 356 times • Downloaded 33 times • Run 0 times
Download the 'Monopoly Probe and Adjust' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


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.


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:




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.


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.


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.


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.


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.


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:


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


At initialization (in setup) qIBase is read into the program variable quantityIntercept.


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)


This section could give some ideas of things for the user to notice while running the model.

/* here, I need to say more */


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


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.


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.


This section could give the names of models in the NetLogo Models Library or elsewhere which are of related interest.


This model was created and written by Steven O. Kimbrough: kimbrough at and The model is
freely downloadable at:

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. 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

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

globals [pstar current-price price-intercept m-price epochOver
         up-data down-data total-revenue probe-count ;episodeLength 
         up-prices down-prices ;monop-prices 
         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)
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

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)
; 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)
  set epochOver false
  set up-data []
  set down-data []

  ] ; end of if(epochOver)

to plot-quantity-price [daPrice]
set-current-plot "quantity-price"
set-plot-y-range 0 price-intercept 
set-plot-x-range 0 quantityIntercept 
set-current-plot-pen "Demand Curve"
plotxy 0 price-intercept
plotxy quantityIntercept 0
set-current-plot-pen "Monopoly Quantity"
plotxy m-quantity 0
plotxy m-quantity m-price
set-current-plot-pen "Monopoly Price"
plotxy 0 m-price
plotxy m-quantity m-price

to-report daRevenue [daQuantity] ; [daPrice]
  let daPrice 0
  set daPrice (price-intercept - (dSlope * daQuantity))
  report daPrice * daQuantity

to-report daPriceIntercept [q-intercept daSlope]
  set price-intercept (q-intercept * daSlope) 
  report price-intercept

to-report daMQuantity
  set m-quantity (price-intercept / ( 2 * dSlope))
  report m-quantity

to-report getMPrice [da-price-intercept da-slope da-m-quantity]
  report (da-price-intercept - (da-slope * da-m-quantity)) 

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 

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))

There is only one version of this model, created about 8 years ago by Steven Kimbrough.

Attached files

No files

This model does not have any ancestors.

This model does not have any descendants.