PageRenderTime 89ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

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

http://scaly.googlecode.com/
Scala | 175 lines | 78 code | 44 blank | 53 comment | 8 complexity | 974e917875d9a5f01fea8a2a4c7b27ca 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 scala.collection.mutable.HashMap
  39. import scaly.parabond.entry.SimpleBond
  40. import scaly.parabond.util.Helper
  41. /**
  42. * This class runs a map-reduce unit test first loading the portfolios to memory.
  43. * @author Ron Coleman, Ph.D.
  44. */
  45. class Mr06 {
  46. /** Number of bond portfolios to analyze */
  47. val PORTF_NUM = 100
  48. /** Connects to the parabond DB */
  49. val mongo = MongoConnection("127.0.0.1")("parabond")
  50. /** Record captured with each result */
  51. case class Result(id: Int, price: Double, bondCount: Int, t0: Long, t1: Long)
  52. /** Write a detailed report */
  53. val details = true
  54. /** Unit test entry point */
  55. @Test
  56. def test {
  57. // Set the number of portfolios to analyze
  58. val arg = System.getProperty("n")
  59. val n = if (arg == null) PORTF_NUM else arg.toInt
  60. println("\n" + this.getClass() + " " + "N = " + n)
  61. val details = if (System.getProperty("details") != null) true else false
  62. val t2 = System.nanoTime
  63. val input = MongoHelper.loadPortfsParallel(n)
  64. val t3 = System.nanoTime
  65. println(" portf load time: %8.4f".format((t3-t2)/1000000000.0))
  66. // Map-reduce the input
  67. val t0 = System.nanoTime
  68. val resultsUnsorted = MapReduce.mapreduceBasic(input, mapping, reducing)
  69. val t1 = System.nanoTime
  70. // Generate the output report
  71. if (details)
  72. println("%6s %10.10s %-5s %-2s".format("PortId", "Price", "Bonds", "dt"))
  73. val list = resultsUnsorted.foldLeft(List[Result]()) { (list, rsult) =>
  74. val (portfId, result) = rsult
  75. list ::: List(result(0))
  76. }
  77. val results = list.sortWith(_.t0 < _.t0)
  78. if (details)
  79. results.foreach { result =>
  80. val id = result.id
  81. val dt = (result.t1 - result.t0) / 1000000000.0
  82. val bondCount = result.bondCount
  83. val price = result.price
  84. println("%6d %10.2f %5d %6.4f %12d %12d".format(id, price, bondCount, dt, result.t1 - t0, result.t0 - t0))
  85. }
  86. val dt1 = results.foldLeft(0.0) { (sum, result) =>
  87. sum + (result.t1 - result.t0)
  88. } / 1000000000.0
  89. val dtN = (t1 - t0) / 1000000000.0
  90. val speedup = dt1 / dtN
  91. val numCores = Runtime.getRuntime().availableProcessors()
  92. val e = speedup / numCores
  93. println("dt(1): %7.4f dt(N): %7.4f cores: %d R: %5.2f e: %5.2f ".
  94. format(dt1, dtN, numCores, speedup, e))
  95. }
  96. /**
  97. * Maps a portfolio to a single price
  98. * @param portId Portfolio id
  99. * @param fitter Curve fitting coefficients
  100. * @returns List of (portf id, bond value))
  101. */
  102. def mapping(portfId: Int, bonds : List[SimpleBond]): List[(Int, Result)] = {
  103. val t0 = System.nanoTime
  104. val price = bonds.foldLeft(0.0) { (sum, bond) =>
  105. val valuator = new SimpleBondValuator(bond, Helper.curveCoeffs)
  106. val price = valuator.price
  107. sum + price
  108. }
  109. // Update the portfolio with the value
  110. val portfsCollecton = mongo("Portfolios")
  111. val portfsQuery = MongoDBObject("id" -> portfId)
  112. val portfsCursor : MongoCursor = portfsCollecton.find(portfsQuery)
  113. val portf = portfsCursor.next
  114. val ids = bonds.map(p => p.id)
  115. val entry = MongoDBObject("id" -> portfId, "instruments" -> ids, "value" -> price)
  116. mongo("Portfolios").insert(entry)
  117. val t1 = System.nanoTime
  118. List((portfId, Result(portfId,price,bonds.size,t0,t1)))
  119. }
  120. /**
  121. * Reduces trivially portfolio prices.
  122. * Since there's only one price per porfolio, there's nothing
  123. * really to reduce!
  124. * @param portfId Portfolio id
  125. * @param vals Bond valuations
  126. * @returns List of portfolio valuation, one per portfolio
  127. */
  128. def reducing(portfId: Int, vals: List[Result]): List[Result] = {
  129. List(vals(0))
  130. }
  131. }