Hotelling's Law

Hotelling's Law preview image

2 collaborators

Uri_dolphin3 Uri Wilensky (Author)

Tags

ccl 

Tagged by Uri Wilensky over 13 years ago

social science 

Tagged by Reuven M. Lerner about 12 years ago

Model group CCL | Visible to everyone | Changeable by group members (CCL)
Model was written in NetLogo 5.0.4 • Viewed 1304 times • Downloaded 99 times • Run 0 times
Download the 'Hotelling's Law' modelDownload this modelEmbed this model

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


WHAT IS IT?

This model is a representation of Hotelling's law (1929), which examines the optimal placement of stores and pricing of their goods in order to maximize profit. In Hotelling's original paper, the stores were confined to a single dimension. This model replicates and extends Hotelling's law, by allowing the stores to move freely on a plane.

In this model, several stores attempt to maximize their profits by moving and changing their prices. Each consumer chooses their store of preference based on the distance to the store and the price of the goods it offers.

HOW IT WORKS

Each consumer adds up the price and distance from each store, and then chooses to go to the store that offers the lowest sum. In the event of a tie, the consumer chooses randomly. The stores can either be constrained to one dimension, in which case all stores operate on a line, or they can be placed on a plane. Under the normal rule, each store tries to move randomly in the four cardinal directions to see if it can gain a larger market share; if not, it does not move. Then each store checks if it can earn a greater profit by increasing or decreasing the price of their goods; if not, it does not change the price. This decision is made without any knowledge of their competitors' strategies. There are two other conditions under which one can run this model: stores can either only change prices, or only move their location.

HOW TO USE IT

Press SETUP to create the stores and a visualization of their starting market share areas.
Press GO to have the model run continuously. Press GO-ONCE to have the model run once. The NUMBER-OF-STORES slider decides how many stores are in the world.

If the LAYOUT chooser is on LINE, then the stores will operate only on one dimension. If it is on PLANE, then the stores will operate in a two dimensional space.

If the RULES chooser is on PRICING-ONLY, then stores can only change their price. If it is on MOVING-ONLY, then the stores can only move. If it is on NORMAL, all stores can change their prices and move.

THINGS TO NOTICE

On the default settings, notice that the two stores end up in very close contact and with minimal prices. This is because each store tries to cut into their competitor's fringe consumers by moving closer and reducing their prices.

Also notice how the shapes of the boundaries end up as perpendicular bisectors or hyperbolic arcs. The distance between the stores and their difference in prices determines the eccentricity of these arcs.

Try increasing the store number to three or more, and notice how the store with the most area is not necessarily the most profitable.

Plots show the prices, areas, and revenues of all stores.

THINGS TO TRY

Try to see how stores behave differently when they are either prohibited from moving or changing their prices.

Try increasing the number of stores. Examine how they behave differently and watch which ones are the most successful. What patterns emerge?

EXTENDING THE MODEL

In this model, information is free, but this is not a realistic assumption. Can you think of a way to add a price when stores try to gain information?

In this model, the stores always seek to increase their profits immediately instead of showing any capacity to plan. They are also incapable of predicting what the competitors might do. Making the stores more intelligent would make this model more realistic.

Maybe one way to make the stores more intelligent would be to have them consider their moving and pricing options in conjunction. Right now, they consider the question "would it be good for me to move North" and "would it be good for me to increase my price" completely separately. But what if they asked "would it be good for me to move North AND increase my price"? Would it make a difference in their decision making?

As of now, the consumers are very static. Is there a way to make the consumers move as well or react in some manner to the competition amongst the stores?

Is there a way to include consumer limitations in their spending power or ability to travel? That is, if all stores charge too much or are too far, the consumer could refuse to go to any store.

In this model, if two or more stores are identical from a consumer's point of view, the consumer will choose to go to one of those at random. If the stores are only slightly different for the consumer, is it possible to have the consumer go to either one?

One can extend this model further by introducing a different layout. How would the patterns change, for example, if the layout of the world were circular? What if we just enable world wrapping?

NETLOGO FEATURES

  • Each store can move up to four times each tick, as each store takes test steps in cardinal directions when deciding on its moving strategy. However, as this model is tick based, the user only sees one step per store.

  • Notice, also, how the plot pens are dynamically created in the setup code of each plot. There has to be one pen for each store, but we don't know in advance how many there will be, so we use the create-temporary-plot-pen primitive to create the pens we need and assign them the right color upon setup.

  • In the procedures where a store chooses a new price or location, we make use of a subtle property of the sort-by primitive: the fact that the order of items in the initial list is preserved in case of ties during sorting. What we do is that we put the "status quo" option at the front of the list possible moves, but shuffle all other possible moves. Because of that, when we sort the moves by potential revenues, the status quo is always preferred in case of equal revenues.

  • What if want to know if all members of a list have a certain property? (This is the equivalent of the "for all" universal quantifier (∀) in predicate logic.) NetLogo doesn't have a primitive to do that directly, but we can easily write it ourselves using the member? and map primitives. The trick is to first map the list to the predicate we want to test. Let's say we want to test if all members of a list are zeros: map [? = 0] [1 0 0] will report [false true true], and map [? = 0] [ 0 0 0 ] will report [true true true]. All we have to is to test the "for all" condition is to make sure that false is not a member of that new list: not member? false map [? = 0] [1 0 0] will report false, and not member? false map [? = 0] [0 0 0] will report true. We use a variant of this in the new-price-task reporter.

  • The procedures for choosing new prices and locations do not actually perform these changes right away. Instead, they report tasks that will be run later in the go procedure. Notice how we put self in a local variable before creating our task: this is because NetLogo tasks "capture" local variables, but not agent context. See the "Tasks" section in the NetLogo Programming guide for more details about this.

RELATED MODELS

  • Voronoi
  • Voronoi - Emergent

CREDITS AND REFERENCES

Hotelling, Harold. (1929). "Stability in Competition." The Economic Journal 39.153: 41 -57. (Stable URL: http://www.jstor.org/stable/2224214 ).

HOW TO CITE

If you mention this model in a publication, we ask that you include these citations for the model itself and for the NetLogo software:

  • Ottino, B., Stonedahl, F. and Wilensky, U. (2009). NetLogo Hotelling's Law model. http://ccl.northwestern.edu/netlogo/models/Hotelling'sLaw. Center for Connected Learning and Computer-Based Modeling, Northwestern Institute on Complex Systems, Northwestern University, Evanston, IL.
  • Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern Institute on Complex Systems, Northwestern University, Evanston, IL.

COPYRIGHT AND LICENSE

Copyright 2009 Uri Wilensky.

CC BY-NC-SA 3.0

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

Commercial licenses are also available. To inquire about commercial licenses, please contact Uri Wilensky at uri@northwestern.edu.

Comments and Questions

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

Click to Run Model

turtles-own [
  price               ; How much each store charges for its product
  area-count          ; The area (market share) that a store held at the end of the last tick
]

patches-own [
  preferred-store     ; The store currently preferred by the consumer
]

globals [
  consumers           ; The patches that will act as consumers, either a vertical line or all patches
]
  
;;;;;;;;;;;;;;;;;;;;;;;;
;;; setup procedures ;;;
;;;;;;;;;;;;;;;;;;;;;;;;

to setup        
  clear-all
  setup-consumers
  setup-stores
  recalculate-area
  reset-ticks
end 

to setup-consumers
  ; Store the agentset of patches that are going to be our
  ; consumers in a global variable for easy reference.
  set consumers ifelse-value (layout = "line")
    [ patches with [ pxcor = 0 ] ]
    [ patches ]
end 

to setup-stores 
  ; We choose as many random colors as the number of stores we want to create
  foreach n-of number-of-stores base-colors [ 
    ; ...and we create a store of each of these colors on random consumer patches
    ask one-of consumers [
      sprout 1 [
        set color ? ; use the color from the list that we are looping through
        set shape "Circle (2)" 
        set size 2 
        set price 10
        set pen-size 5
      ]
    ]
  ]
end 

to go
  ; We accumulate location and price changes as list of tasks to be run later
  ; in order to simulate simultaneous decision making on the part of the stores
     
  let location-changes ifelse-value (rules = "pricing-only")
    [ (list) ] ; if we are doing "pricing-only", the list of moves is empty
    [ [ new-location-task ] of turtles ]
  
  let price-changes ifelse-value (rules = "moving-only")
    [ (list) ] ; if we are doing "moving-only", the list of price changes is empty
    [ [ new-price-task ] of turtles ]

  foreach location-changes run
  foreach price-changes run
  recalculate-area
  tick  
end 

to recalculate-area
  ; Have each consumer (patch) indicate its preference by 
  ; taking on the color of the store it chooses
  ask consumers [ 
    set preferred-store choose-store
    set pcolor ([ color ] of preferred-store + 2)
  ]
  ask turtles [
    set area-count count consumers with [ preferred-store = myself ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;
;;; turtle procedures ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;

; Have the store consider the benefits of taking a unit step in each of the four cardinal directions
; and report a task that will allow the chosen location change to be enacted later

to-report new-location-task

  ; we want the neighbors4 in random order, but we want to turn them from an agentset to a list
  ; and `sort` is the way to do that, hence the weird `shuffle sort` expression
  let possible-moves shuffle sort (neighbors4 with [ member? self consumers ])
  
  if area-count > 0 [
    ; Only consider the status quo if we already have a market share, but if we consider it,
    ; put it at the front of the list so it is favored in case of ties in sort-by
    set possible-moves fput patch-here possible-moves
  ]

  ; pair the potiental moves with their revenues, and sort these pairs by revenues
  let moves-with-market-shares
    sort-by [ last ?1 > last ?2 ]
    map [ list ? (market-share-if-move-to ?) ] possible-moves

  ; report the first item of the first pair, i.e., the move with the best revenues
  let chosen-location first first moves-with-market-shares

  let store self ; put self in a local variable so that it can be "captured" by the task
  report task [
    ask store [
      pen-down 
      move-to chosen-location
      pen-up
    ]
  ]
end 

; report the market share area the store would have if it moved to destination

to-report market-share-if-move-to [ destination ] ; turtle procedure
  let current-position patch-here
  move-to destination
  let market-share-at-destination potential-market-share
  move-to current-position
  report market-share-at-destination
end 

to-report potential-market-share
  report count consumers with [ choose-store = myself ]
end 

; Have the store consider the revenue from hypothetically increasing or decreasing its price by one unit
; and report a task that will allow the chosen price change to be enacted later

to-report new-price-task

  ; We build a list of candidate prices, keeping the status quo in first, but having -1 and +1 in random 
  ; order after that. This order is going to be preserved by the `sort-by` primitive in case of ties,
  ; and we always want the status quo to win in this case, but -1 and +1 to have equal chances
  let possible-prices fput price shuffle list (price - 1) (price + 1)

  ; pair each potential price change with its potential revenue
  ; and sort them in decreasing order of revenue
  let prices-with-revenues
    sort-by [ last ?1 > last ?2 ]
    map [ list ? (potential-revenue ?) ] possible-prices

  let all-zeros? (not member? false map [ last ? = 0 ] prices-with-revenues)
  let chosen-price ifelse-value (all-zeros? and price > 1)
    [ price - 1 ] ; if all potential revenues are zero, the store lowers its price as an emergency procedure if it can
    [ first first prices-with-revenues ] ; in any other case, we pick the price with the best potential revenues

  let store self ; put self in a local variable so that it can be "captured" by the task
  report task [
    ask store [
      set price chosen-price
    ]
  ]
end 

to-report potential-revenue [ target-price ]
  let current-price price
  set price target-price
  let new-revenue (potential-market-share * target-price)
  set price current-price
  report new-revenue
end 

;;;;;;;;;;;;;;;;;;;;;;;
;;; patch procedure ;;;
;;;;;;;;;;;;;;;;;;;;;;;

; report the store with the best deal, defined as the smallest sum of price and distance

to-report choose-store
  report min-one-of turtles [ (price) + (distance myself) ]
end 


; Copyright 2009 Uri Wilensky.
; See Info tab for full copyright and license.

There are 4 versions of this model.

Uploaded by When Description Download
Uri Wilensky over 12 years ago Updated to NetLogo 5.0.4 Download this version
Uri Wilensky almost 13 years ago Updated version tag Download this version
Uri Wilensky almost 13 years ago Updated to version from NetLogo 5.0.3 distribution Download this version
Uri Wilensky over 13 years ago Updated from NetLogo 5.0 Download this version

Attached files

File Type Description Last updated
Hotelling's Law.png preview Preview for 'Hotelling's Law' over 12 years ago, by Uri Wilensky Download
Hotelling's Law.png preview Preview for 'Hotelling's Law' over 12 years ago, by Uri Wilensky Download

This model does not have any ancestors.

This model does not have any descendants.