msfz751

Prosper Vector Class

Jun 13th, 2015
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ' ########################################
  2. ' #         Vector Class Module          #
  3. ' ########################################
  4. ' Auxiliary library to work with Petroleum Experts (TM) OpenServer.
  5. ' Part of the SimpleOpenServer package, developed by Patricio Panichelli.
  6. ' Some rights reserved (c) www.SimpleOpenServer.com/license
  7. ' For documentation, visit www.SimpleOpenServer.com/docs
  8. ' SOS Version:              1.0.0
  9. ' Developed & tested with:  IPM 9.0
  10. '
  11. Option Explicit
  12. Option Base 0
  13. Private xValues
  14. Enum vDirection
  15.     printDown
  16.     printRight
  17. End Enum
  18. Enum sDirection
  19.     leftToRight
  20.     rightToLeft
  21. End Enum
  22. Const NotFound = -1E+30
  23.  
  24. ' ++++++++++++++++++++++++++++
  25. ' Private sub Class_Initialize
  26. ' ++++++++++++++++++++++++++++
  27. ' Initializes the class with the defaults
  28. Private Sub Class_Initialize()
  29.     ReDim xValues(0 To 1, -1 To -1)
  30. End Sub
  31.  
  32. ' ++++++++++++++++++++
  33. ' Public Sub transpose
  34. ' ++++++++++++++++++++
  35. ' Exchanges the X and Y coordinates of the vector
  36. Public Sub transpose()
  37.     Dim newVec As Variant, i As Integer
  38.     ReDim newVec(0 To 1, 0 To UBound(xValues, 2))
  39.     For i = 0 To UBound(xValues, 2)
  40.         newVec(0, i) = xValues(1, i)
  41.         newVec(1, i) = xValues(0, i)
  42.     Next
  43.     xValues = newVec
  44. End Sub
  45.  
  46. ' +++++++++++++++++
  47. ' Public Function Y
  48. ' +++++++++++++++++
  49. ' Returns the Y value for a given X from a vector.
  50. ' Linear interpolation
  51. ' Warning: will extrapolate if X is not included in the domain
  52. Public Function Y(ByVal X As Double) As Double
  53.     If Me.points < 2 Then err.Raise 2020, "Y", "Trying to guess Y from X but vector has only " & CStr(Me.points) & " point(s)."
  54.     Dim i As Integer
  55.     For i = 0 To UBound(xValues, 2)
  56.         If xValues(0, i) > X Then Exit For
  57.     Next
  58.     If i = 0 Then i = i + 1
  59.     If i > UBound(xValues, 2) Then i = UBound(xValues, 2)
  60.     If (xValues(0, i) - xValues(0, i - 1)) = 0 Then
  61.         ' Try to avoid division by zero
  62.        Y = xValues(1, i - 1)
  63.     Else
  64.         Y = xValues(1, i - 1) + (X - xValues(0, i - 1)) / (xValues(0, i) - xValues(0, i - 1)) * (xValues(1, i) - xValues(1, i - 1))
  65.     End If
  66. End Function
  67.  
  68. ' ++++++++++++++++++++
  69. ' Public Function dYdX
  70. ' ++++++++++++++++++++
  71. ' Returns the derivative value for a given X from a vector.
  72. ' Uses quadratic fit
  73. ' CAUTION: will extrapolate if X is not included in the domain
  74. Public Function dYdX(ByVal X As Double) As Double
  75.     Dim numPoints As Integer
  76.     numPoints = Me.points
  77.     If numPoints < 2 Then err.Raise 2020, "dYdX", "Trying to guess dYdX from X but vector has only " & CStr(numPoints) & " point(s)."
  78.     If numPoints = 2 Then
  79.         ' 2 points - Straight line
  80.        dYdX = (xValues(1, 1) - xValues(1, 0)) / (xValues(0, 1) - xValues(0, 0))
  81.     Else
  82.         ' 3 or more points
  83.        Dim i As Long, coeffs
  84.         For i = 0 To numPoints - 1
  85.             If xValues(0, i) > X Then Exit For
  86.         Next
  87.         If i = 0 Then i = i + 1
  88.         If i > numPoints - 1 Then i = i - 1
  89.         If i = numPoints - 1 Then i = i - 1
  90.         coeffs = pFitQuadAtIndex(i)
  91.         dYdX = 2 * coeffs(0) * X + coeffs(1) ' 2 a X + b
  92.    End If
  93. End Function
  94.  
  95. ' ++++++++++++++++++++++
  96. ' Public Function XfromY
  97. ' ++++++++++++++++++++++
  98. ' Returns the X value that corresponds to a given Y from a vector.
  99. ' Returns NotFound if the value was not found
  100. Function XfromY(Y As Double, Optional searchDirection As Variant) As Double
  101.     If Me.points < 2 Then err.Raise 2020, "XfromY", "Trying to guess X from Y but vector has only " & CStr(Me.points) & " point(s)."
  102.     If IsMissing(searchDirection) Then searchDirection = sDirection.rightToLeft
  103.     Dim i As Integer
  104.     If searchDirection = sDirection.rightToLeft Then
  105.         For i = UBound(xValues, 2) To 1 Step -1
  106.             If Sgn(xValues(1, i) - Y) <> Sgn(xValues(1, i - 1) - Y) Then Exit For
  107.         Next
  108.         If i = 0 Then
  109.             XfromY = NotFound
  110.             Exit Function
  111.         End If
  112.         XfromY = xValues(0, i - 1) + (Y - xValues(1, i - 1)) / (xValues(1, i) - xValues(1, i - 1)) * (xValues(0, i) - xValues(0, i - 1))
  113.     Else
  114.         For i = 0 To UBound(xValues, 2) - 1 Step 1
  115.             If Sgn(xValues(1, i) - Y) <> Sgn(xValues(1, i + 1) - Y) Then Exit For
  116.         Next
  117.         If i = UBound(xValues, 2) Then
  118.             XfromY = NotFound
  119.             Exit Function
  120.         End If
  121.         XfromY = xValues(0, i) + (xValues(1, i) - Y) / (xValues(1, i) - xValues(1, i + 1)) * (xValues(0, i + 1) - xValues(0, i))
  122.     End If
  123. End Function
  124.  
  125. ' +++++++++++++++++++
  126. ' Public Property min
  127. ' +++++++++++++++++++
  128. ' Returns the Minimum value of a vector
  129. ' By default is the Y value, but pass an "X" as
  130. ' parameter and you will get the X corresponding
  131. ' to the maximum.
  132. Public Property Get min(Optional coordinate)
  133.     Dim i As Integer, mV As Double, returnX As Boolean
  134.     If UCase(CStr(coordinate)) = "X" Then returnX = True
  135.     mV = 1E+30
  136.     For i = 0 To UBound(xValues, 2)
  137.         If CDbl(xValues(1, i)) < mV Then
  138.             mV = xValues(1, i)
  139.             If returnX Then
  140.                 min = xValues(0, i)
  141.             Else
  142.                 min = xValues(1, i)
  143.             End If
  144.         End If
  145.     Next
  146. End Property
  147.  
  148. ' +++++++++++++++++++
  149. ' Public Property max
  150. ' +++++++++++++++++++
  151. ' Returns the Maximum value of a vector
  152. ' By default is the Y value, but pass an "X" as
  153. ' parameter and you will get the X corresponding
  154. ' to the maximum.
  155. Public Property Get max(Optional coordinate)
  156.     Dim i As Integer, mV As Double, returnX As Boolean
  157.     If UCase(CStr(coordinate)) = "X" Then returnX = True
  158.     mV = -1E+30
  159.     For i = 0 To UBound(xValues, 2)
  160.         If CDbl(xValues(1, i)) > mV Then
  161.             mV = xValues(1, i)
  162.             If returnX Then
  163.                 max = xValues(0, i)
  164.             Else
  165.                 max = xValues(1, i)
  166.             End If
  167.         End If
  168.     Next
  169. End Property
  170.  
  171. ' ++++++++++++++++++++
  172. ' Public Property last
  173. ' ++++++++++++++++++++
  174. ' Returns the last value of a vector
  175. ' By default is the Y value, but pass an "X" as
  176. ' parameter and you will get the X.
  177. Public Property Get last(Optional coordinate)
  178.     If UCase(CStr(coordinate)) = "X" Then
  179.         last = xValues(0, UBound(xValues, 2))
  180.     Else
  181.         last = xValues(1, UBound(xValues, 2))
  182.     End If
  183. End Property
  184.  
  185. ' +++++++++++++++++++++
  186. ' Public Property first
  187. ' +++++++++++++++++++++
  188. ' Returns the first value of a vector.
  189. ' By default is the Y value, but pass an "X" as
  190. ' parameter and you will get the X.
  191. Public Property Get first(Optional coordinate)
  192.     If UCase(CStr(coordinate)) = "X" Then
  193.         first = xValues(0, 0)
  194.     Else
  195.         first = xValues(1, 0)
  196.     End If
  197. End Property
  198.  
  199. ' ++++++++++++++++++++++
  200. ' Public Property values
  201. ' ++++++++++++++++++++++
  202. ' Returns the values as a variant variable
  203. Public Property Get values() As Variant
  204.     values = xValues
  205. End Property
  206.  
  207. ' ++++++++++++++++++++++++
  208. ' Public Sub newFromValues
  209. ' ++++++++++++++++++++++++
  210. ' Sets the vector equal to a variant object.
  211. ' Useful to initialize with values
  212. Public Sub newFromValues(ByVal values As Variant)
  213.     xValues = values
  214.     pReverseIfNecessary
  215. End Sub
  216.  
  217. ' +++++++++++++++++++++++
  218. ' Public Sub newFromRange
  219. ' +++++++++++++++++++++++
  220. ' Sets the vector equal to a range.
  221. ' Must be a 2-column vertical range, with X values in the left and Y values in the right
  222. Public Sub newFromRange(ByVal rng)
  223.     If TypeName(rng) = "String" Then rng = range(rng)
  224.     Dim newVec, i As Integer, numRows As Integer
  225.     If TypeName(rng) = "Range" Then
  226.         numRows = rng.rows.Count - 1
  227.     Else
  228.         numRows = UBound(rng, 1) - 1
  229.     End If
  230.     ReDim newVec(0 To 1, 0 To numRows)
  231.     For i = 0 To UBound(newVec, 2)
  232.         If rng(i + 1, 1) = "" Or rng(i + 1, 2) = "" Then Exit For
  233.         newVec(0, i) = CDbl(rng(i + 1, 1))
  234.         newVec(1, i) = CDbl(rng(i + 1, 2))
  235.     Next
  236.     ReDim Preserve newVec(0 To 1, 0 To i - 1)
  237.     xValues = newVec
  238.     pReverseIfNecessary
  239. End Sub
  240.  
  241. ' +++++++++++++++++++
  242. ' Public Sub addPoint
  243. ' +++++++++++++++++++
  244. ' Adds the given point (x, y) to the vector
  245. ' Useful to create point-based vectors
  246. Public Sub addPoint(X As Double, Y As Double)
  247.     Dim numRows As Integer
  248.     numRows = UBound(xValues, 2) + 1
  249.     ReDim Preserve xValues(0 To 1, 0 To numRows)
  250.     xValues(0, numRows) = X
  251.     xValues(1, numRows) = Y
  252. End Sub
  253.  
  254. ' +++++++++++++++++++
  255. ' Public Sub multiply
  256. ' +++++++++++++++++++
  257. ' Multiplies two vectors' Y parameters (v1 + v2)
  258. ' Or will multiply a vector by a number
  259. Public Sub multiply(ByVal vectorOrValue As Variant)
  260.     Dim typN As String
  261.     typN = TypeName(vectorOrValue)
  262.     If typN = "Integer" Or typN = "Double" Or typN = "Long" Then
  263.         pMultByNumber CDbl(vectorOrValue)
  264.     ElseIf typN = "Vector" Then
  265.         pMultByVector vectorOrValue.values
  266.     Else
  267.         err.Raise 2020, "add", "Trying to add vector or value, but no value or vector was passed"
  268.     End If
  269. End Sub
  270.  
  271. ' +++++++++++++++++++++++++
  272. ' Private Sub pMultByNumber
  273. ' +++++++++++++++++++++++++
  274. ' Multiplies the Y-coordinate by  a double
  275. Private Sub pMultByNumber(value As Double)
  276.     Dim i As Integer
  277.     For i = 0 To UBound(xValues, 2)
  278.         xValues(1, i) = xValues(1, i) * value
  279.     Next
  280. End Sub
  281.  
  282. ' +++++++++++++++++++++++++
  283. ' Private Sub pMultByVector
  284. ' +++++++++++++++++++++++++
  285. ' Multiplies the Y-coordinates of two vectors
  286. ' Both vectors need to be of the same length and the same x-coords
  287. Private Sub pMultByVector(v2 As Variant)
  288.     If UBound(xValues, 2) = UBound(v2, 2) Then
  289.         Dim i As Integer
  290.         For i = 0 To UBound(xValues, 2)
  291.             If xValues(0, i) <> v2(0, i) Then err.Raise 2020, "multiply", "When multiplying two vectors, the X-Coordinates were not compatible."
  292.             xValues(1, i) = xValues(1, i) * v2(1, i)
  293.         Next
  294.     Else
  295.         err.Raise 2020, "add", "Tried to multiply two vectors, but sizes are not compatible."
  296.     End If
  297. End Sub
  298.  
  299. ' ++++++++++++++
  300. ' Public Sub add
  301. ' ++++++++++++++
  302. ' Adds two vectors' Y parameters (v1 + v2)
  303. ' Or will add a vector to a number
  304. Public Sub add(ByVal vectorOrValue As Variant)
  305.     Dim typN As String
  306.     typN = TypeName(vectorOrValue)
  307.     If typN = "Integer" Or typN = "Double" Or typN = "Long" Then
  308.         pAddNumber CDbl(vectorOrValue)
  309.     ElseIf typN = "Vector" Then
  310.         pAddVector vectorOrValue.values
  311.     Else
  312.         err.Raise 2020, "add", "Trying to add vector or value, but no value or vector was passed"
  313.     End If
  314. End Sub
  315.  
  316. ' ++++++++++++++++++++
  317. ' Public Sub subtract
  318. ' ++++++++++++++++++++
  319. ' Subtracts two vectors' Y parameters (v1 - v2)
  320. ' Or will subtract a number from a vector
  321. Public Sub subtract(ByVal vectorOrValue As Variant)
  322.     Dim typN As String
  323.     typN = TypeName(vectorOrValue)
  324.     If typN = "Integer" Or typN = "Double" Or typN = "Long" Then
  325.         pAddNumber -CDbl(vectorOrValue)
  326.     ElseIf typN = "Vector" Then
  327.         vectorOrValue.multiply -1
  328.         pAddVector vectorOrValue.values
  329.         vectorOrValue.multiply -1
  330.     Else
  331.         err.Raise 2020, "subtract", "Trying to subtract vector or value, but no value or vector was passed"
  332.     End If
  333. End Sub
  334.  
  335. ' ++++++++++++++++++++++
  336. ' Private Sub pAddNumber
  337. ' ++++++++++++++++++++++
  338. ' Adds a double to the Y-coordinate
  339. Private Sub pAddNumber(value As Double)
  340.     Dim i As Integer
  341.     For i = 0 To UBound(xValues, 2)
  342.         xValues(1, i) = xValues(1, i) + value
  343.     Next
  344. End Sub
  345.  
  346. ' ++++++++++++++++++++++
  347. ' Private Sub pAddVector
  348. ' ++++++++++++++++++++++
  349. ' Adds a Y-coordinates of two vectors
  350. ' Both vectors need to be of the same length and the same x-coords
  351. Private Sub pAddVector(v2 As Variant)
  352.     If UBound(xValues, 2) = UBound(v2, 2) Then
  353.         Dim i As Integer
  354.         For i = 0 To UBound(xValues, 2)
  355.             If xValues(0, i) <> v2(0, i) Then err.Raise 2020, "add", "When adding two vectors, the X-Coordinates were not compatible."
  356.             xValues(1, i) = xValues(1, i) + v2(1, i)
  357.         Next
  358.     Else
  359.         err.Raise 2020, "add", "Tried to add two vectors, but sizes are not compatible."
  360.     End If
  361. End Sub
  362.  
  363. ' ++++++++++++++++++++++
  364. ' Public Sub printInCell
  365. ' ++++++++++++++++++++++
  366. ' prints the values of a vector in the worksheet, starting in the range specified
  367. ' Optional values > direction: [printDown] | printRight
  368. '                 > printX:    [True]      | False
  369. Public Sub printInCell(inRange As range, Optional direction As Variant, Optional printX As Variant)
  370.     If IsMissing(printX) Then printX = True
  371.     printX = CBool(printX)
  372.     If IsMissing(direction) Then direction = vDirection.printDown
  373.    
  374.     If printX Then
  375.         If direction = vDirection.printRight Then
  376.             inRange.Resize(2, UBound(xValues, 2) + 1) = xValues
  377.         Else
  378.             inRange.Resize(UBound(xValues, 2) + 1, 2) = Application.transpose(xValues)
  379.         End If
  380.     Else
  381.         If direction = vDirection.printRight Then
  382.             inRange.Resize(1, UBound(xValues, 2) + 1) = pGetYValues()
  383.         Else
  384.             inRange.Resize(UBound(xValues, 2) + 1, 1) = Application.transpose(pGetYValues())
  385.         End If
  386.     End If
  387. End Sub
  388.  
  389. ' +++++++++++++++++++++++++++++++
  390. ' Private Sub pReverseIfNecessary
  391. ' +++++++++++++++++++++++++++++++
  392. ' If x Values are in descending order, it reverses the vector.
  393. ' Will only check for first two values to see if it is reversed
  394. Private Sub pReverseIfNecessary()
  395.     Dim nPoints As Long
  396.     nPoints = Me.points
  397.     If nPoints <= 1 Then Exit Sub
  398.     If xValues(0, 0) > xValues(0, 1) Then
  399.         Dim newValues, i As Long
  400.         ReDim newValues(0 To 1, 0 To nPoints - 1)
  401.         For i = 0 To nPoints - 1
  402.             newValues(0, i) = xValues(0, nPoints - 1 - i)
  403.             newValues(1, i) = xValues(1, nPoints - 1 - i)
  404.         Next
  405.         xValues = newValues
  406.     End If
  407. End Sub
  408.  
  409. ' ++++++++++++++++++++++
  410. ' Public Property points
  411. ' ++++++++++++++++++++++
  412. ' Returns the amount of points in a vector.
  413. Public Property Get points() As Integer
  414.     points = UBound(xValues, 2) + 1
  415. End Property
  416.  
  417. ' +++++++++++++++++++
  418. ' Public Function MSE
  419. ' +++++++++++++++++++
  420. ' Returns the mean square error between two vectors
  421. ' calculated as SUM( dif^2 ) / nPoints
  422. ' Used in the match function
  423. Public Function MSE(ByVal points As Vector) As Double
  424.     Dim i As Integer, sqD As Double, PointValues, numPoints As Integer
  425.     numPoints = points.points
  426.     PointValues = points.values
  427.     For i = 0 To numPoints - 1
  428.         sqD = sqD + (Me.Y(CDbl(PointValues(0, i))) - PointValues(1, i)) ^ 2
  429.     Next
  430.     MSE = sqD / numPoints
  431. End Function
  432.  
  433. ' ++++++++++++++++++++++++++++++++
  434. ' Private function pFitQuadAtIndex
  435. ' ++++++++++++++++++++++++++++++++
  436. ' fits a quadratic around point at index i
  437. ' using a quadratic function ax2 + bx + c
  438. ' returns [ a, b, c ]
  439. Private Function pFitQuadAtIndex(i As Long)
  440.     pFitQuadAtIndex = pFitQuad(CDbl(xValues(0, i - 1)), CDbl(xValues(1, i - 1)), _
  441.                                CDbl(xValues(0, i)), CDbl(xValues(1, i)), _
  442.                                CDbl(xValues(0, i + 1)), CDbl(xValues(1, i + 1)))
  443. End Function
  444.  
  445. ' +++++++++++++++++++++++++
  446. ' Private function pFitQuad
  447. ' +++++++++++++++++++++++++
  448. ' given three points 1,2,3: fits them using a quadratic function ax2 + bx + c
  449. ' returns [ a, b, c ]
  450. Private Function pFitQuad(x1 As Double, y1 As Double, x2 As Double, y2 As Double, x3 As Double, y3 As Double) As Variant
  451.     Dim result(2), X(1 To 3, 1 To 3) As Double, Y(1 To 3, 1 To 1) As Double, c
  452.     X(1, 1) = 1
  453.     X(1, 2) = x1
  454.     X(1, 3) = x1 * x1
  455.     X(2, 1) = 1
  456.     X(2, 2) = x2
  457.     X(2, 3) = x2 * x2
  458.     X(3, 1) = 1
  459.     X(3, 2) = x3
  460.     X(3, 3) = x3 * x3
  461.     Y(1, 1) = y1
  462.     Y(2, 1) = y2
  463.     Y(3, 1) = y3
  464.     c = Application.MMult(Application.MInverse(X()), Y())
  465.     result(0) = c(3, 1)
  466.     result(1) = c(2, 1)
  467.     result(2) = c(1, 1)
  468.     pFitQuad = result
  469. End Function
  470.  
  471.  
  472. ' ++++++++++++++++++++++++++++
  473. ' Private Function pGetYValues
  474. ' ++++++++++++++++++++++++++++
  475. ' Returns a 1-dimension (real vector) of the Y values of our vector
  476. Private Function pGetYValues() As Variant
  477.     Dim returnedArr As Variant, i As Integer
  478.     ReDim returnedArr(0 To UBound(xValues, 2))
  479.     For i = 0 To UBound(xValues, 2)
  480.         returnedArr(i) = xValues(1, i)
  481.     Next
  482.     pGetYValues = returnedArr
  483. End Function
Advertisement
Add Comment
Please, Sign In to add comment