PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/ParaBond/src/scaly/parabond/test/Mr04.scala

http://scaly.googlecode.com/
Scala | 204 lines | 90 code | 54 blank | 60 comment | 8 complexity | e7b51c55ad6a783caca0d93367878e87 MD5 | raw file
  1. /*
  2. * Copyright (c) Scaly Contributors
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the Scaly Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. package scaly.parabond.test
  28. import org.scalatest.junit.JUnitSuite
  29. import org.junit.Assert._
  30. import org.junit.Test
  31. import scaly.parabond.mr.MapReduce
  32. import com.mongodb.casbah.MongoConnection
  33. import com.mongodb.casbah.commons.MongoDBObject
  34. import com.mongodb.casbah.MongoCursor
  35. import scaly.parabond.util.MongoHelper
  36. import scaly.parabond.value.SimpleBondValuator
  37. import scala.util.Random
  38. import scaly.parabond.util.Helper
  39. /**
  40. * This class runs a map-reduce unit test for n portfolios in the
  41. * parabond database. It uses one bond per actor.
  42. * @author Ron Coleman, Ph.D.
  43. */
  44. class Mr04 {
  45. /** Number of bond portfolios to analyze */
  46. val PORTF_NUM = 10
  47. /** Connects to the parabond DB */
  48. val mongo = MongoConnection(MongoHelper.getHost)("parabond")
  49. /** Record captured with each result */
  50. case class Result(id : Int, price: Double, bondCount: Int, t0: Long, t1: Long)
  51. /** Initialize the random number generator */
  52. val ran = new Random(0)
  53. /** Write a detailed report */
  54. val details = true
  55. val numCores = Runtime.getRuntime().availableProcessors()
  56. /** Unit test entry point */
  57. @Test
  58. def test {
  59. // Set the number of portfolios to analyze
  60. val arg = System.getProperty("n")
  61. val n = if(arg == null) PORTF_NUM else arg.toInt
  62. var me = this.getClass().getSimpleName()
  63. var outFile = me + "-dat.txt"
  64. var fos = new java.io.FileOutputStream(outFile,true)
  65. var os = new java.io.PrintStream(fos)
  66. os.print(me+" "+ "N: "+n+" ")
  67. val details = if(System.getProperty("details") != null) true else false
  68. // Build the portfolio list
  69. // Connect to the portfolio collection
  70. val t2 = System.nanoTime
  71. val portfsCollecton = mongo("Portfolios")
  72. val input = (1 to n).foldLeft(List[(Int,Int)]()) { (list, p) =>
  73. val r = ran.nextInt(100000)+1
  74. // Retrieve the portfolio
  75. val portfsQuery = MongoDBObject("id" -> r)
  76. val portfsCursor: MongoCursor = portfsCollecton.find(portfsQuery)
  77. // Get the bonds in the portfolio
  78. val bondIds = MongoHelper.asList(portfsCursor, "instruments")
  79. val pairs = bondIds.foldLeft(List[(Int,Int)]()) { (sum, id) =>
  80. sum ::: List((r,id))
  81. }
  82. list ++ pairs
  83. }
  84. val t3 = System.nanoTime
  85. // Map-reduce the input
  86. val t0 = System.nanoTime
  87. // val resultsUnsorted = MapReduce.coarseMapReduce(input, mapping, reducing,numCores,numCores)
  88. val resultsUnsorted = MapReduce.mapreduceBasic(input, mapping, reducing)
  89. val t1 = System.nanoTime
  90. // Generate the output report
  91. if(details)
  92. println("%6s %10.10s %-5s %-2s".format("PortId","Price","Bonds","dt"))
  93. val list = resultsUnsorted.foldLeft(List[Result]()) { (list, rsult) =>
  94. val (portfId, result) = rsult
  95. list ::: List(result(0))
  96. }
  97. val results = list.sortWith(_.t0 < _.t0)
  98. if (details)
  99. results.foreach { result =>
  100. val id = result.id
  101. val dt = (result.t1 - result.t0) / 1000000000.0
  102. val bondCount = result.bondCount
  103. val price = result.price
  104. println("%6d %10.2f %5d %6.4f %12d %12d".format(id, price, bondCount, dt, result.t1 - t0, result.t0 - t0))
  105. }
  106. val dt1 = results.foldLeft(0.0) { (sum,result) =>
  107. sum + (result.t1 - result.t0)
  108. } / 1000000000.0
  109. val dtN = (t3 - t2 + t1 - t0) / 1000000000.0
  110. val speedup = dt1 / dtN
  111. val e = speedup / numCores
  112. os.println("dt(1): %7.4f dt(N): %7.4f cores: %d R: %5.2f e: %5.2f ".
  113. format(dt1,dtN,numCores,speedup,e))
  114. os.flush
  115. os.close
  116. println(me+" DONE! %d %7.4f".format(n,dtN))
  117. }
  118. /**
  119. * Maps a portfolio to a single price
  120. * @param portId Portfolio id
  121. * @param fitter Curve fitting coefficients
  122. * @returns List of (portf id, bond value))
  123. */
  124. def mapping(portfId: Int, bondId : Int): List[(Int,Result)] = {
  125. val t0 = System.nanoTime
  126. val bondsCollection = mongo("Bonds")
  127. val bondQuery = MongoDBObject("id" -> bondId)
  128. val bondCursor: MongoCursor = bondsCollection.find(bondQuery)
  129. val bond = MongoHelper.asBond(bondCursor)
  130. val valuator = new SimpleBondValuator(bond, Helper.curveCoeffs)
  131. val price = valuator.price
  132. val t1 = System.nanoTime
  133. List((portfId, Result(portfId,price,1,t0,t1)))
  134. }
  135. /**
  136. * Reduces trivially portfolio prices.
  137. * Since there's only one price per porfolio, there's nothing
  138. * really to reduce!
  139. * @param portfId Portfolio id
  140. * @param vals Bond valuations
  141. * @returns List of portfolio valuation, one per portfolio
  142. */
  143. def reducing(portfId: Int,vals: List[Result]): List[Result] = {
  144. val total = vals.foldLeft(Result(portfId,0,0,0,0)) { (sum, result) =>
  145. Result(portfId,sum.price+result.price,sum.bondCount+1,sum.t0+result.t0,sum.t1+result.t1)
  146. }
  147. //Result(id : Int, price: Double, bondCount: Int, t0: Long, t1: Long)
  148. List(total)
  149. }
  150. }