Skip to content
Prev 302351 / 398506 Next

Head or Tails game

Two possible solutions below.
On Fri, 3 Aug 2012, darnold wrote:

            
In general, vectorizing means doing a bunch of calculations in each
step. Keep in mind that apply and friends are basically convenience
notation for loops (they are convenient, but are best applied after
a bunch of vectorization has already been applied).

In some cases multiple levels of loops can be vectorized together.
I was only able to manage one level, but choosing the RIGHT level
to vectorize is important... get as many calculations done at each
step of code as possible to get the fastest speedup.

The ideas:
  1) Have "sample" do as many coin flips at once as possible. Fold
     the results into a matrix to make it look like multiple
     sets of results.
  2) Use vector logical tests to perform the game logic. Use
     vector indexing if appropriate to look at "previous" results.
  3) Use automatic conversion of logical results to integer for
     accumulating counts of successes.
  4) Consider using cumsum or similar vectorized operations.
  5) Since there are more games than moves in each game, consider
     simulating each step of all games vectorially to minimize
     the number of looping steps.

The code:

#------------------------------------
# Head or Tails game

# Approach by vectorizing each game evaluation and looping over games
loopbygame <- function( results ) {
   gameleadcount <- function(v) {
    pot <- cumsum( v )
    sum( pot > 0 | c( FALSE, 0==pot[ -1 ] & 0 != pot[ -nrow( results ) ] ) )
   }
   apply(results,2,gameleadcount)
}

# Approach by vectorizing one step from all games and looping over steps
loopbymove <- function( results ) {
   pot <- rep( 0, ncol( results ) )
   leadcount <- rep( 0, ncol( results ) )
   for ( moveno in 1:nrow( results ) ) {
     oldpot <- pot
     pot <- pot + results[ moveno, ]
     leadcount <- leadcount + ( pot > 0 | 0 == pot & 0 != oldpot )
   }
   leadcount
}

gamelen <- 40
gamecount <- 10000
set.seed( 123 )
results <- matrix( sample( c( -1, 1 ), gamelen*gamecount, replace=TRUE  )
                  , ncol=gamecount )

system.time( ans1 <- loopbymove( results ) )
system.time( ans2 <-loopbygame( results ) )
all.equal( ans1, ans2 )

My results:
user  system elapsed
   0.040   0.000   0.037
user  system elapsed
   0.224   0.000   0.219
[1] TRUE
You are welcome.  Note that on this "great list" normally requests for 
"ideas" on optimization without a concrete, reproducible code example of 
some type are groused at for not showing sufficient research on your part 
and for essentially asking us to do your work for you. In this case I
found the problem interesting enough to respond in spite of your lack
of reproducible (even if inefficient) code.

---------------------------------------------------------------------------
Jeff Newmiller                        The     .....       .....  Go Live...
DCN:<jdnewmil at dcn.davis.ca.us>        Basics: ##.#.       ##.#.  Live Go...
                                       Live:   OO#.. Dead: OO#..  Playing
Research Engineer (Solar/Batteries            O.O#.       #.O#.  with
/Software/Embedded Controllers)               .OO#.       .OO#.  rocks...1k