PageRenderTime 105ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://scaly.googlecode.com/
Scala | 220 lines | 103 code | 59 blank | 58 comment | 9 complexity | 1829b88be84f9dcf0f16b18b3afcfce1 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.collection.JavaConverters._
  38. import scala.util.Random
  39. import scaly.parabond.util.Helper
  40. import scaly.parabond.entry.SimpleBond
  41. import com.mongodb.BasicDBList
  42. /**
  43. * This class uses parallel collections to price n portfolios in the
  44. * parabond database using the composite fine-grain algorithm.
  45. * @author Ron Coleman, Ph.D.
  46. */
  47. class Par05 {
  48. /** Number of bond portfolios to analyze */
  49. val PORTF_NUM = 100
  50. /** Connects to the parabond DB */
  51. val mongo = MongoConnection(MongoHelper.getHost)("parabond")
  52. /** Initialize the random number generator */
  53. val ran = new Random(0)
  54. /** Write a detailed report */
  55. val details = false
  56. /** Record captured with each result */
  57. case class Result(id : Int, price: Double, bondCount: Int, t0: Long, t1: Long)
  58. case class Data(portfId: Int, bonds:List[SimpleBond], result: Result)
  59. @Test
  60. def test {
  61. // Set the number of portfolios to analyze
  62. val arg = System.getProperty("n")
  63. val n = if(arg == null) PORTF_NUM else arg.toInt
  64. var me = this.getClass().getSimpleName()
  65. var outFile = me + "-dat.txt"
  66. var fos = new java.io.FileOutputStream(outFile,true)
  67. var os = new java.io.PrintStream(fos)
  68. os.print(me+" "+ "N: "+n+" ")
  69. val details = if(System.getProperty("details") != null) true else false
  70. // Build the portfolio list
  71. val inputs = for(i <- 0 until n) yield Data(ran.nextInt(100000)+1,null, null)
  72. // Build the portfolio list
  73. val now = System.nanoTime
  74. val outputs = inputs.par.map(priced)
  75. val t1 = System.nanoTime
  76. // Generate the detailed output report
  77. if(details) {
  78. println("%6s %10.10s %-5s %-2s".format("PortId","Price","Bonds","dt"))
  79. outputs.foreach { output =>
  80. val id = output.result.id
  81. val dt = (output.result.t1 - output.result.t0) / 1000000000.0
  82. val bondCount = output.result.bondCount
  83. val price = output.result.price
  84. println("%6d %10.2f %5d %6.4f %12d %12d".format(id, price, bondCount, dt, output.result.t1 - now, output.result.t0 - now))
  85. }
  86. }
  87. val dt1 = outputs.foldLeft(0.0) { (sum,result) =>
  88. sum + (result.result.t1 - result.result.t0)
  89. } / 1000000000.0
  90. val dtN = (t1 - now) / 1000000000.0
  91. val speedup = dt1 / dtN
  92. val numCores = Runtime.getRuntime().availableProcessors()
  93. val e = speedup / numCores
  94. os.println("dt(1): %7.4f dt(N): %7.4f cores: %d R: %5.2f e: %5.2f ".
  95. format(dt1,dtN,numCores,speedup,e))
  96. os.flush
  97. os.close
  98. println(me+" DONE! %d %7.4f".format(n,dtN))
  99. }
  100. def priced(input: Data): Data = {
  101. // Value each bond in the portfolio
  102. val t0 = System.nanoTime
  103. // Connect to the portfolio collection
  104. val portfsCollecton = mongo("Portfolios")
  105. // Retrieve the portfolio
  106. val portfId = input.portfId
  107. val portfsQuery = MongoDBObject("id" -> portfId)
  108. val portfsCursor : MongoCursor = portfsCollecton.find(portfsQuery)
  109. // Connect to the bonds collection
  110. val bondsCollection = mongo("Bonds")
  111. // Get the bonds in the portfolio
  112. val bids = MongoHelper.asList(portfsCursor,"instruments")
  113. val bondIds = for(i <- 0 until bids.size) yield Data(bids(i),null,null)
  114. // val bondIds = asList(portfsCursor,"instruments")
  115. val output = bondIds.par.map { bondId =>
  116. // Get the bond from the bond collection
  117. val bondQuery = MongoDBObject("id" -> bondId.portfId)
  118. val bondCursor: MongoCursor = bondsCollection.find(bondQuery)
  119. val bond = MongoHelper.asBond(bondCursor)
  120. val valuator = new SimpleBondValuator(bond, Helper.curveCoeffs)
  121. val price = valuator.price
  122. new SimpleBond(bond.id,bond.coupon,bond.freq,bond.tenor,price)
  123. }.par.reduce(sum)
  124. // { (a: SimpleBond, b:SimpleBond) =>
  125. // new SimpleBond(0,0,0,0,a.maturity+b.maturity)
  126. // }
  127. // val outputStage2 = outputStage1.par.reduce { (a: SimpleBond, b:SimpleBond) =>
  128. // new SimpleBond(0,0,0,0,a.maturity+b.maturity)
  129. // }
  130. MongoHelper.updatePrice(input.portfId,output.maturity)
  131. val t1 = System.nanoTime
  132. Data(input.portfId,null,Result(input.portfId,output.maturity,bondIds.size,t0,t1))
  133. }
  134. def sum(a: SimpleBond, b:SimpleBond) : SimpleBond = {
  135. new SimpleBond(0,0,0,0,a.maturity+b.maturity)
  136. }
  137. /** Converts mongo cursor to scala Data objects */
  138. def asList(cursor: MongoCursor,field : String) : List[Data] = {
  139. val cur = cursor.map { p =>
  140. // Get mongo ids which is a BasicDBList -- but Scala
  141. // can't handle this with FP so we need to convert it
  142. // an immutable list that FP can handle
  143. val ids = p.get(field)
  144. ids match {
  145. case listAsJava : BasicDBList =>
  146. val listInteger = listAsJava.asScala
  147. val list = listInteger.map { p =>
  148. p match {
  149. case intAsJava : java.lang.Integer =>
  150. Data(intAsJava.toInt,null,null)
  151. }
  152. }
  153. list.toList
  154. case _ =>
  155. null
  156. }
  157. }
  158. // cur is an Iterator[List[Data]] of size 1
  159. cur.next
  160. }
  161. }