How can I access a variable outside of a function in Swift before it runs in a while loop? - swift

First of all, try not to rip me to shreds :) I am relatively new to programming in general and this is my first question on StackOverflow!
This is hopefully a simple question, how can I return the "var m = ..." line outside of the function given below? I am trying to implement the Bisection Numerical Method (seen on rayweiderlich.com) but for a different equation. I am trying to access the variable outside of the function in order to update a label on a viewcontroller. Note: The iterative variable I am trying to solve does output correctly and that number is the 0.8789. Therefore, I think the algorithm is correct. Here is the tutorial link https://www.raywenderlich.com/99559/numeric-algorithms-using-playgrounds and my version of tutorials code:
//: Playground - noun: a place where people can play
import UIKit
func bisection(x: Double) -> Double {
var lower = 0.0
var upper = x
let constant1 = Double((1+2*60))
let constant2 = Double(1+4*60)
var m = (constant1 - pow(constant2, 0.5)) / (2.0*60.0) //This returns the number I want (0.8789)
let epsilon = 1e-3
while (fabs(m * m - x) > epsilon) {
m = (lower + upper)/2
if m * m > x {
upper = m
print(m)
} else {
lower = m
print(m)
}
}
print(m)
return m //This returns the number I DON'T want (0.9995)
}
let bis = bisection(x: 1.0)
//somewhere around here is where I would like to use the "m" variable to update a label in a view controller

import UIKit
func bisection(x: Double) -> Double {
let constant1 = Double((1+2*60))
let constant2 = Double(1+4*60)
let m = (constant1 - pow(constant2, 0.5)) / (2.0*60.0)
return m
}
let bis = bisection(x: 1.0)
print(bis)
Is this what you want?

Related

Generating a simple algebraic expression in swift

I'm looking to create a function that returns a solve for x math equation that can be preformed in ones head (Clearly thats a bit subjective but I'm not sure how else to phrase it).
Example problem: (x - 15)/10 = 6
Note: Only 1 x in the equation
I want to use the operations +, -, *, /, sqrt (Only applied to X -> sqrt(x))
I know that let mathExpression = NSExpression(format: question) converts strings into math equations but when solving for x I'm not sure how to go about doing this.
I previously asked Generating random doable math problems swift for non solving for x problems but I'm not sure how to convert that answer into solving for x
Edit: Goal is to generate an equation and have the user solve for the variable.
Since all you want is a string representing an equation and a value for x, you don't need to do any solving. Just start with x and transform it until you have a nice equation. Here's a sample: (copy and paste it into a Playground to try it out)
import UIKit
enum Operation: String {
case addition = "+"
case subtraction = "-"
case multiplication = "*"
case division = "/"
static func all() -> [Operation] {
return [.addition, .subtraction, .multiplication, .division]
}
static func random() -> Operation {
let all = Operation.all()
let selection = Int(arc4random_uniform(UInt32(all.count)))
return all[selection]
}
}
func addNewTerm(formula: String, result: Int) -> (formula: String, result: Int) {
// choose a random number and operation
let operation = Operation.random()
let number = chooseRandomNumberFor(operation: operation, on: result)
// apply to the left side
let newFormula = applyTermTo(formula: formula, number: number, operation: operation)
// apply to the right side
let newResult = applyTermTo(result: result, number: number, operation: operation)
return (newFormula, newResult)
}
func applyTermTo(formula: String, number:Int, operation:Operation) -> String {
return "\(formula) \(operation.rawValue) \(number)"
}
func applyTermTo(result: Int, number:Int, operation:Operation) -> Int {
switch(operation) {
case .addition: return result + number
case .subtraction: return result - number
case .multiplication: return result * number
case .division: return result / number
}
}
func chooseRandomNumberFor(operation: Operation, on number: Int) -> Int {
switch(operation) {
case .addition, .subtraction, .multiplication:
return Int(arc4random_uniform(10) + 1)
case .division:
// add code here to find integer factors
return 1
}
}
func generateFormula(_ numTerms:Int = 1) -> (String, Int) {
let x = Int(arc4random_uniform(10))
var leftSide = "x"
var result = x
for i in 1...numTerms {
(leftSide, result) = addNewTerm(formula: leftSide, result: result)
if i < numTerms {
leftSide = "(" + leftSide + ")"
}
}
let formula = "\(leftSide) = \(result)"
return (formula, x)
}
func printFormula(_ numTerms:Int = 1) {
let (formula, x) = generateFormula(numTerms)
print(formula, " x = ", x)
}
for i in 1...30 {
printFormula(Int(arc4random_uniform(3)) + 1)
}
There are some things missing. The sqrt() function will have to be implemented separately. And for division to be useful, you'll have to add in a system to find factors (since you presumably want the results to be integers). Depending on what sort of output you want, there's a lot more work to do, but this should get you started.
Here's sample output:
(x + 10) - 5 = 11 x = 6
((x + 6) + 6) - 1 = 20 x = 9
x - 2 = 5 x = 7
((x + 3) * 5) - 6 = 39 x = 6
(x / 1) + 6 = 11 x = 5
(x * 6) * 3 = 54 x = 3
x * 9 = 54 x = 6
((x / 1) - 6) + 8 = 11 x = 9
Okay, let’s assume from you saying “Note: Only 1 x in the equation” that what you want is a linear equation of the form y = 0 = β1*x + β0, where β0 and β1 are the slope and intercept coefficients, respectively.
The inverse of (or solution to) any linear equation is given by x = -β0/β1. So what you really need to do is generate random integers β0 and β1 to create your equation. But since it should be “solvable” in someone’s head, you probably want β0 to be divisible by β1, and furthermore, for β1 and β0/β1 to be less than or equal to 12, since this is the upper limit of the commonly known multiplication tables. In this case, just generate a random integer β1 ≤ 12, and β0 equal to β1 times some integer n, 0 ≤ n ≤ 12.
If you want to allow simple fractional solutions like 2/3, just multiply the denominator and the numerator into β0 and β1, respectively, taking care to prevent the numerator or denominator from getting too large (12 is again a good limit).
Since you probably want to make y non-zero, just generate a third random integer y between -12 and 12, and change your output equation to y = β1*x + β0 + y.
Since you mentioned √ could occur over the x variable only, that is pretty easy to add; the solution (to 0 = β1*sqrt(x) + β0) is just x = (β0/β1)**2.
Here is some very simple (and very problematic) code for generating random integers to get you started:
import func Glibc.srand
import func Glibc.rand
import func Glibc.time
srand(UInt32(time(nil)))
print(rand() % 12)
There are a great many answers on this website that deal with better ways to generate random integers.

How do I "tune my program" to get relative errors down to E-10?

The problem
I wrote a recursive program to calculate the first 26 values of the spherical Bessel functions for a given input x. The program seems to start to accumulate relatively large errors at j_8(x). Here is the output of some code that found the relative errors based on some known high precision spherical Bessel function values for the first 25 SBF's (l=0 to l=24):
5.27753443514687e-16
9.21595688945492e-16
3.02006896635059e-15
7.62720601251909e-14
4.57824286846449e-12
4.42939097671948e-10
6.23673401270476e-08
1.20281992792456e-05
0.00304187901758528
0.976196008573827
387.486227014647
186360.170424407
106776056.913571
71856241567.0684
56117385601216.0
5.03357079061797e+16
5.13915094291702e+19
5.92532834322625e+22
7.6613338261931e+25
1.10398479254694e+29
1.76304629085447e+32
3.10469930465156e+35
6.00134333269024e+38
1.26807670217943e+42
2.91783063679757e+45
As you can see, after the j_8(x) value the error is starting to increase. The problem simply states that I should "tune" my program to get the error down to E-10, but how do I do this? I'm completely lost...
The code:
import Foundation
var x: Double = 0.0
var j_up_val: Double = 0.0
func j_up(x_val: Double, l_val: Double) -> Double {
if l_val == 0 {
j_up_val = sin(x_val)/x_val
} else if l_val == 1 {
j_up_val = (sin(x_val)/pow(x_val,2.0)) - (cos(x_val)/x_val)
} else if l_val == 2 {
j_up_val = ((2*(l_val-1)+1)/x_val) * ((sin(x_val)/pow(x_val,2.0)) - cos(x_val)/x_val) - sin(x_val)/x_val
} else {
let l2: Double = l_val - 1
let l3: Double = l_val - 2
j_up_val = ((2*(l_val-1)+1)/x_val)*j_up(x_val: x, l_val: l2) - j_up(x_val: x, l_val: l3)
}
return j_up_val
}
x = 1
print("x:", x)
for i in 0...25 {
var i_double: Double = 0.0
i_double = Double(i)
print("l:", i)
print(j_up(x_val: x, l_val: i_double))
print(" \n")
}
print("**********************")

IBM Swift Sandbox cannot resolve call to CoreFoundation function

I'm mucking around with the beta of the IBM Swift Sandbox; does anyone know why I'm getting the following error for the code below?:
LLVM ERROR: Program used external function 'CFAbsoluteTimeGetCurrent' which could not be resolved!
// A demonstration of both iterative and recursive algorithms for computing the Fibonacci numbers.
import CoreFoundation
// A recursive algorithm to compute the Fibonacci numbers.
func fibRec (n : Int) -> Double {
return (Double)(n < 3 ? 1 : fibRec(n - 1) + fibRec(n - 2))
}
// An iterative algorithm to compute the Fibonacci numbers.
func fibIter (n : Int) -> Double {
var f2 = 0.0
var f1 = 1.0
var f0 = 1.0
for _ in 0 ..< n {
f2 = f1 + f0
f0 = f1
f1 = f2
}
return f0
}
// Initialise array to hold algorithm execution times.
var fibTimes = [Double]()
// i is the ith Fibonacci number to be computed.
for i in 120..<129 {
var fibNum = 0.0
var fibSum = 0.0
// j is the number of times to compute F(i) to obtain average.
for j in 0..<5 {
// Set start time.
let startTime = CFAbsoluteTimeGetCurrent()
// Uses the recursive algorithm.
// fibNum = fibRec(i)
// Uses the iterative algorithm.
fibNum = fibIter(i)
fibTimes.insert(CFAbsoluteTimeGetCurrent() - startTime, atIndex: j)
}
// Compute the average execution time.
for p in fibTimes {
fibSum += p
}
fibSum = fibSum / 5
print("Fibonacci number \(i) is: \(fibNum)")
print("Execution time: \(fibSum) seconds")
}
You just have to import Foundation as well.
I am not sure why this is needed (I hope someone that does know, could shed some light on this), but it works.
To clarify, you have to import them both.
import Foundation
import CoreFoundation
Alternatively, Glibc has clock() which returns an Int instead. For example:
import Glibc
struct StartTimer {
let start = clock()
var elapsed = -1
mutating func stop() { elapsed = clock() - start }
}
var timer = StartTimer()
/* do your work */
timer.stop()
print("Elapsed Time: \(timer.elapsed)")

Swift automatic function inversion

If I have a function like:
func evaluateGraph(sender: GraphView, atX: Double) -> Double? {
return function?(atX)
}
Where function is a variable declared earlier and it is a mathematical expression (like x^2). How can I find the inverse of the univariate function in swift at a point (atX)?
Assuming that you just want to know the inverse function in your GraphView (which is hopefully not infinite) you can use something like this:
// higher percision -> better accuracy, start...end: Interval, f: function
func getZero(#precision: Int, var #start: Double, var #end: Double, f: Double -> Double) -> Double? {
let fS = f(start)
let fE = f(end)
let isStartNegative = fS.isSignMinus
if isStartNegative == fE.isSignMinus { return nil }
let fMin = min(fS, fE)
let fMax = max(fS, fE)
let doublePrecision = pow(10, -Double(precision))
while end - start > doublePrecision {
let mid = (start + end) / 2
let fMid = f(mid)
if fMid < fMin || fMax < fMid {
return nil
}
if (fMid > 0) == isStartNegative {
end = mid
} else {
start = mid
}
}
return (start + end) / 2
}
// same as above but it returns an array of points
func getZerosInRange(#precision: Int, #start: Double, #end: Double, f: Double -> Double) -> [Double] {
let doublePrecision = pow(10, -Double(precision))
/// accuracy/step count between interval; "antiproportional" performance!!!!
let stepCount = 100.0
let by = (end - start) / stepCount
var zeros = [Double]()
for x in stride(from: start, to: end, by: by) {
if let xZero = getZero(precision: precision, start: x, end: x + by, f) {
zeros.append(xZero)
}
}
return zeros
}
// using currying; all return values should be elements of the interval start...end
func inverse(#precision: Int, #start: Double, #end: Double, f: Double -> Double)(_ x: Double) -> [Double] {
return getZerosInRange(precision: precision, start: start, end: end) { f($0) - x }
}
let f = { (x: Double) in x * x }
// you would pass the min and max Y values of the GraphView
// type: Double -> [Double]
let inverseF = inverse(precision: 10, start: -10, end: 10, f)
inverseF(4) // outputs [-1.999999999953436, 2.000000000046564]
Interestingly this code rund in a playground in about 0.5 second which I didn't expect.
You could create an inverse function to do the opposite.
So f(x) = y inverse f' gives f'(y) = x.
So if your defined function is to square the input then the inverse is to return the square root and so on.
You might run into trouble with something like that though as f'(1) = 1 and -1 in the case where f(x) returns the square.
Short of actually writing the inverse method, the only way to actually inversely infer what input gave a provided output, the best we can do is write our program to make guesses until it's within a certain accuracy.
So, for example, let's say we have the square function:
func square(input: Double) -> Double {
return input * input
}
Now, if we don't want to right the inverse of this function (which actually has two inputs for any given output), then we have to write a function to guess.
func inverseFunction(output: Double, function: (Double)->Double) -> Double
This takes a double representing the output, and a function (the one that generated the output), and returns its best-guess at the answer.
So, how do we guess?
Well, the same way we do in pre-calculus and the early parts of any calculus 1 class. Pick a starting number, run it through the function, compare the result to the output we're looking for. Record the delta. Pick a second number, run it through the function, compare the result to the output we're looking for. Record the delta, compare it to the first delta.
Continually do this until you have minimized the delta to an acceptable accuracy level (0.1 delta okay? 0.01? 0.0001?). The smaller the delta, the longer it takes to calculate. But it's going to take a long time no matter what.
As for the guessing algorithm? That's a math question that I'm not capable of answering. I wouldn't even know where to begin with that.
In the end, your best bet is to simply write inverse functions for any function you'd want to inverse.

Linear regression - accelerate framework in Swift

My first question here at Stackoverflow... hope my question is specific enough.
I have an array in Swift with measurements at certain dates. Like:
var myArray:[(day: Int, mW: Double)] = []
myArray.append(day:0, mW: 31.98)
myArray.append(day:1, mW: 31.89)
myArray.append(day:2, mW: 31.77)
myArray.append(day:4, mW: 31.58)
myArray.append(day:6, mW: 31.46)
Some days are missing, I just didn't take a measurement... All measurements should be on a line, more or less. So I thought about linear regression. I found the Accelerate framework, but the documentation is missing and I can't find examples.
For the missing measurements I would like to have a function, with as input a missing day and as output a best guess, based on the other measurements.
func bG(day: Int) -> Double {
return // return best guess for measurement
}
Thanks for helping out.
Jan
My answer doesn't specifically talk about the Accelerate Framework, however I thought the question was interesting and thought I'd give it a stab. From what I gather you're basically looking to create a line of best fit and interpolate or extrapolate more values of mW from that. To do that I used the Least Square Method, detailed here: http://hotmath.com/hotmath_help/topics/line-of-best-fit.html and implemented this in Playgrounds using Swift:
// The typealias allows us to use '$X.day' and '$X.mW',
// instead of '$X.0' and '$X.1' in the following closures.
typealias PointTuple = (day: Double, mW: Double)
// The days are the values on the x-axis.
// mW is the value on the y-axis.
let points: [PointTuple] = [(0.0, 31.98),
(1.0, 31.89),
(2.0, 31.77),
(4.0, 31.58),
(6.0, 31.46)]
// When using reduce, $0 is the current total.
let meanDays = points.reduce(0) { $0 + $1.day } / Double(points.count)
let meanMW = points.reduce(0) { $0 + $1.mW } / Double(points.count)
let a = points.reduce(0) { $0 + ($1.day - meanDays) * ($1.mW - meanMW) }
let b = points.reduce(0) { $0 + pow($1.day - meanDays, 2) }
// The equation of a straight line is: y = mx + c
// Where m is the gradient and c is the y intercept.
let m = a / b
let c = meanMW - m * meanDays
In the code above a and b refer to the following formula from the website:
a:
b:
Now you can create the function which uses the line of best fit to interpolate/extrapolate mW:
func bG(day: Double) -> Double {
return m * day + c
}
And use it like so:
bG(3) // 31.70
bG(5) // 31.52
bG(7) // 31.35
If you want to do fast linear regressions in Swift, I suggest using the Upsurge framework. It provides a number of simple functions that wrap the Accelerate library and so you get the benefits of SIMD on either iOS or OSX
without having to worry about the complexity of vDSP calls.
To do a linear regression with base Upsurge functions is simply:
let meanx = mean(x)
let meany = mean(y)
let meanxy = mean(x * y)
let meanx_sqr = measq(x)
let slope = (meanx * meany - meanxy) / (meanx * meanx - meanx_sqr)
let intercept = meany - slope * meanx
This is essentially what is implemented in the linregress function.
You can use it with an array of [Double], other classes such as RealArray (comes with Upsurge) or your own objects if they can expose contiguous memory.
So a script to meet your needs would look like:
#!/usr/bin/env cato
import Upsurge
typealias PointTuple = (day: Double, mW:Double)
var myArray:[PointTuple] = []
myArray.append((0, 31.98))
myArray.append((1, 31.89))
myArray.append((2, 31.77))
myArray.append((4, 31.58))
myArray.append((6, 31.46))
let x = myArray.map { $0.day }
let y = myArray.map { $0.mW }
let (slope, intercept) = Upsurge.linregress(x, y)
func bG(day: Double) -> Double {
return slope * day + intercept
}
(I left in the appends rather than using literals as you are likely programmatically adding to your array if it is of significant length)
and full disclaimer: I contributed the linregress code. I hope to also add the co-efficient of determination at some point in the future.
To estimate the values between different points, you can also use SKKeyframeSequence from SpriteKit
https://developer.apple.com/documentation/spritekit/skinterpolationmode/spline
import SpriteKit
let sequence = SKKeyframeSequence(keyframeValues: [0, 20, 40, 60, 80, 100], times: [64, 128, 256, 512, 1024, 2048])
sequence.interpolationMode = .spline // .linear, .step
let estimatedValue = sequence.sample(atTime: CGFloat(1500)) as! Double // 1500 is the value you want to estimate
print(estimatedValue)