Functional way to map a geometric series in Swift - swift

I have an array of size n. I would like to fill it with values from a geometric series with a functional approach.
What function should I use?
The result should be an array such as :
[a, a^2, a^3, ... a^n]

You can use sequence(first:next:) to compute powers
of a by repeated multiplication, limit the (lazily evaluated) sequence with prefix(_:) to the desired number of entries, and then create an array from the truncated sequence. Example:
let a = 0.5 // The base
let n = 4 // The maximal exponent
let series = Array(sequence(first: a, next: { $0 * a }).prefix(n))
print(series) // [0.5, 0.25, 0.125, 0.0625]
Another option can be to enumerate the sequence without creating an
actual array:
for x in sequence(first: a, next: { $0 * a }).prefix(n) {
// do something with `x`
}

You can create such geometric series by simply calling map on a range and doing the power operation inside map.
func createGeometricSeries(ofSize n:Int, _ a:Int)->[Int]{
return (1...n).map({Int(pow(Double(a), Double($0)))})
}
createGeometricSeries(ofSize: 3,2) //[2,4,8]

You can use map for that,
let resultingArray = yourArray.map({ a * $0 })
resulting array is the array that will meet your requirement
You can find more about it here in Apple Documentation.

Related

How to map inputs to outputs with same output and uniform distribution guarantees?

I have a set of inputs (in my case Strings) of variable size N, that I need to map to a set of outputs (in my case indexes of an array) of fixed size M. So, I basically need a function like:
fn map(input: String) -> usize;
I need to guarantee 2 things:
For any input X I must always return the same output Y. For example: every time I pass the string "hello" to my function the returned value must always be the same, for example 1.
The distribution of the values returned must be uniform, that is, for an infinite number of inputs, the average of the same returned values must be the same. For example, if I have M = 4 different values to return, and I have N = 100 different inputs, the number of inputs mapped to each output must be ideally equal to 25.
I came up with the following piece of code:
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
fn main() {
let bucket = Bucket::new(5);
let inputs = ["hello", "world", "house", "hi"];
for input in &inputs {
let output = bucket.get(input);
assert_eq!(output, bucket.get(input));
println!("{} -> {}", input, output);
}
}
pub struct Bucket {
values: Vec<usize>,
}
impl Bucket {
pub fn new(size: usize) -> Self {
let values = (0..size).collect();
Bucket { values }
}
pub fn get<T: Hash>(&self, id: &T) -> usize {
let mut hasher = DefaultHasher::new();
Hash::hash(id, &mut hasher);
let index = (hasher.finish() % self.values.len() as u64) as usize;
self.values[index]
}
}
Link to Playground
I think that the above code guarantees the 1st point (always same output for same input), but not necessarily the 2nd (uniformity of the distribution).
Is there a fast implementation of such a function so that both points are guaranteed?
I think you are correct that the 1st point is ok with your implementation.
Regarding the 2nd point: It depends on what DefaultHasher does. In practice it may be good enough, but there is another technique that will lead to your requirement fulfilled:
Have a counter m, initially 0.
Have a HashMap mapping String to usize.
Whenever you want to get the result, look up the given string in the HashMap:
If the string is already present, return the associated value.
If the string is not already present:
Add a new entry to the HashMap that maps the given string to the current value of m.
Increment m by 1.
If m==M, reset m to 0.

how do I get the index from this function

this is demo of iOS Charts library (LineChart) and I want to input my data instead of arc4random data.
My data is in Array so I have to approach with index but I can't understand the (0..<count).map { (i) -> ChartDataEntry code.
func setChartValues(_ count : Int = 24) {
let values = (0..<count).map { (i) -> ChartDataEntry in
let val = Double(arc4random_uniform(UInt32(count))+3)
return ChartDataEntry(x: Double(i), y: val)
}
let set1 = LineChartDataSet(entries: values , label : "DataSet 1")
let data = LineChartData(dataSet: set1)
self.lineChartView.data = data
}
It seems you are new to iOS and swift. What you are looking for is an understanding of the functionning of closures in swift, plus the map function which is called an high order function
from apple doc ( https://developer.apple.com/documentation/swift/array/3017522-map ) :
Returns an array containing the results of mapping the given closure over the sequence’s elements.
In other words it maps your array into another array, according to the trailing closure you passed as a parameter.
In your specific case here his how to read it :
(0..<count) : creates an array of count lengh
example : if count = 4 then (0..<count) is [0, 1, 2, 3]
As said previously the map function will transform each of your element into another ( therefore keeping the length of the array ).
in your case val = Double(arc4random_uniform(UInt32(count))+3) will be equal to a random number calculated with count value, and create a new ChartDataEntry with this random value.
to sum it up the whole code is just saying "I will create a count length array of random ChartDataEntry", I guess as a mockup
I suggest you to read about closures here :
https://medium.com/the-andela-way/closures-in-swift-8aef8abc9474
and high order functions ( such as map(_:) ) here :
https://medium.com/#abhimuralidharan/higher-order-functions-in-swift-filter-map-reduce-flatmap-1837646a63e8
let values = (0.. ChartDataEntry in
let val = Double(arc4random_uniform(UInt32(count))+3)
return ChartDataEntry(x: Double(i), y: val)
}
The value mapped and return is you can say a hash function. (arc4random).
It index you are taking is just setting X axis of the chart like 0 , 1 ,2 etc...
and your graph Y it set according to the functions return (arc4random)

Segmentation fault using Swift Accelerate vDSP_ctoz

I'm trying to convert an interleaved DSPComplex vector to a DSPSplitComplex vector, using vDSP_ctoz from the Swift Accelerate library. The last line of the code below produces the error Segmentation fault: 11
I don't understand why vDSP_ctoz would try to access out-of-bound memory when I've allocated large vectors and am only trying to process a small number of elements. The vectors are size 2048 and the argument for N (number of elements to process) in vDSP_ctoz is 1.
I've also tried using different stride and N values when calling vDSP_ctoz, to no avail.
// set stride values
let dspComplexStride = MemoryLayout<DSPComplex>.stride
let dspSplitComplexStride = MemoryLayout<DSPSplitComplex>.stride
// make interleaved vector
var interleaved = UnsafeMutablePointer<DSPComplex>.allocate(capacity: 2048)
for index in 0..<16 {
interleaved[index] = DSPComplex(real: Float(2*index), imag: Float(2*index+1))
}
// make split vector
var splitComplex = UnsafeMutablePointer<DSPSplitComplex>.allocate(capacity: 2048)
vDSP_ctoz(
interleaved, dspComplexStride, splitComplex, dspSplitComplexStride, 1
)
DSPSplitComplex is a structure containing pointers arrays,
so you need a single DSPSplitComplex element and must allocate
storage for its realp and imagp properties.
The "stride" arguments are not measured in bytes but in "element" units.
So you pass __IZ == 1 because you want to fill contiguous elements
in the destination arrays.
It may not be obvious that you have to pass __IC == 2 for the source array, i.e.
the stride of the source array is given in Float units and not in
DSPComplex units. This can be deduced from the vDSP_ctoz documentation
which mentions that the function effectively does
for (n = 0; n < N; ++n)
{
Z->realp[n*IZ] = C[n*IC/2].real;
Z->imagp[n*IZ] = C[n*IC/2].imag;
}
Finally, the last argument of vDSP_ctoz is the number of elements to
process.
Putting it all together, this is how it should work:
import Accelerate
let N = 16
var interleaved = UnsafeMutablePointer<DSPComplex>.allocate(capacity: N)
for index in 0..<N {
interleaved[index] = DSPComplex(real: Float(2*index), imag: Float(2*index+1))
}
let realp = UnsafeMutablePointer<Float>.allocate(capacity: N)
let imagp = UnsafeMutablePointer<Float>.allocate(capacity: N)
var splitComplex = DSPSplitComplex(realp: realp, imagp: imagp)
vDSP_ctoz(interleaved, 2, &splitComplex, 1, vDSP_Length(N))
for index in 0..<N {
print(splitComplex.realp[index], splitComplex.imagp[index])
}
and of course you have to release the memory eventually.

How can I search through this array for a specific value then return the other value in the tuple?

I have a large array of (x,y) pairs:
P =
[
(0.0, 500000.09999999998),
(0.001, 18.332777589999999),
(0.002, 18.332221480000001),
(0.0030000000000000001, 18.331665000000001),
(0.0040000000000000001, 18.331108140000001),
(0.0050000000000000001, 18.33055092),
(0.0060000000000000001, 18.32999332),
...
]
I now need to use this in my code. I need to search for a specific x-value and, if the x-value exists, return its corresponding y-value.
Note: If there is a better format I could put my (x,y) pairs in, please feel free to let me know. For example, 2 separate arrays where one holds the x-values and the other holds the y-values. Then I could use the index to find the corresponding y-value or something.
Edit:
A user made a very good point in the comments: how can I reliably compare x == 0.001?
The way I will be using my code is this: I am evaluating a function f(x) at values of x. However, if at a particular value of x there is a y value in the P array, then I need to do an extra subtraction calculation (the details of which are not too important here). The problem, then, is that what if I pass the x value 0.001 in there and the P array does not have a correpsonding y value, but it does have one for 0.001000000009?? Then the code will say there is no value, but in reality it is reasonably close to the intended x value.
I'd suggest to let your array to be an array of CGPoints. It's simply:
A structure that contains a point in a two-dimensional coordinate
system.
However, if you want to get the y values based on searching the x:
let myArray = [
(0.0, 500000.09999999998),
(0.001, 18.332777589999999),
(0.002, 18.332221480000001),
(0.0030000000000000001, 18.331665000000001),
(0.0040000000000000001, 18.331108140000001),
(0.0050000000000000001, 18.33055092),
(0.0060000000000000001, 18.32999332),
]
// this array should contains y values for a given x value
// for example, I search the x value of 0.0
let yValues = myArray.filter { $0.0 == 0.0 }.map { $0.1 }
print(yValues) // [500000.09999999998]
Hope this helped.
A good way of doing this is by declaring this function:
func getValueFromTuples(tupleArr:[(Double,Double)],n:Double)->Double?{
for tuple in tupleArr{
if tuple.0 == n{
return tuple.1
}
}
return nil
}
Then, you can use it like this:
var tupleArray: [(Double,Double)] = [(1.0, 12.0),(2.0,23.0),(3.0,34.0),(4.0,45.0),(5.0,56.0)]
var x:Double = 1.0
print(getValueFromTuples(tupleArr: tupleArray,n:x) ?? "No value found") // 12.0
Where the n argument is the value to be found, the tuple is the key-value pair formed by the numbers and getValueFromTuples returns the value y if x has been found, else nil.
This returns "No value found" if the value does not exist in the array of tuples.
Hope this helps!
Your x value all seem to increase by 0.001. If that is the case, you could also calculate the index and return the y value at this index. This would be a lot more efficient.
func calculateIndex(forX x: Double) -> Int {
let increase = 0.001
return Int(x/0.001)
}
You can use the find method to find the index of the x value and then return the y value. I would multiply your values by 1000 and then compare the Int instead of comparing Double.
func findYValue(forX x: Double) -> Double? {
let multiply = 1000
let x = Int(multiply*x)
if let index = array.index(where: { Int($0.0 * multiply) == x }) {
return array[index].1 //found the y value
}
return nil //x is not in the array
}
Instead of using tuples, I would personally use CGPoint. The class has an x and a y property, which makes your code more readable.
Microsoft gives a very thorough explanation of how to compare 2 doubles. The basic premise is that you need to define a certain level of tolerance. The article the explores how to pick a good tolerance in most cases.
Here's code translated to Swift:
func areEqual(_ lhs: Double, _ rhs: Double, units: Int = 3) -> Bool {
let lValue = Int64(bitPattern: lhs.bitPattern)
let rValue = Int64(bitPattern: rhs.bitPattern)
let delta = lValue - rValue
return abs(delta) <= Int64(units)
}
Test:
var n = 0.0
for _ in 0..<10 {
n += 0.1
}
// n should equal 1 but it does not
print(n == 1.0) // false
print(areEqual(1.0, n)) // true
Back to your problem, it becomes straight forward after you defined how to test for equality in 2 doubless:
let x = 0.003
if let y = p.first(where: { areEqual($0.0, x) })?.1 {
print(y)
}

How do you assign a slice of numbers to an array in swift

x is an object that holds an array called point.
x implements the subscript operator so you can do things, like x[i] to get the array's ith element (of type T, which is usually an Int or Double).
This is what I want to do:
x[0...2] = [0...2]
But I get an error that says ClosedInterval<T> is not convertible to Int/Double.
Edit1:
Here is my object x:
let x = Point<Double>(dimensions:3)
For kicks and giggles: define x as [1.0,2.0,0.0]
I can get the first n elements via x[0...2].
What I want to know is how to update x[0...2] to hold [0.0, 0.0.0.0] in one fell swoop. Intuitively, I would want to do x[0...2] = [0...2]. This does not work as can be seen in the answers. I want to update x without iteration (on my end) and by hiding the fact that x is not an array (even though it is not).
[0...2] is an array with one element which, at best, will be a Range<Int> from 0 through 2. You can't assign that to a slice containing, say, Ints.
x[0...2] on the other hand is (probably) a slice, and Sliceable only defines a get subscript, not a setter. So even if the types were more compatible - that is, if you tried x[0...2] = 0...2, which at least is attempting to replace a range within x with the values of a similarly-sized collection - it still wouldn't work.
edit: as #rintaro points out, Array does support a setter subscript for ranges – so if x were a range you could do x[0...2] = Slice(0...2) – but it has to be a slice you assign, so I'd still go with replaceRange.
If what you mean is you want to replace entries 0 through 2 with some values, what you want is replaceRange, as long as your collection conforms to RangeReplaceableCollection (which, for example, Array does):
var x = [0,1,2,3,4,5]
var y = [200,300,400]
x.replaceRange(2..<5, with: y)
// x is now [0,1,200,300,400,5]
Note, the replaced range and y don't have to be the same size, the collection will expand/contract as necessary.
Also, y doesn't have to an array, it can be any kind of collection (has to be a collection though, not a sequence). So the above code could have been written as:
var x = [0,1,2,3,4,5]
var y = lazy(2...4).map { $0 * 100 }
x.replaceRange(2..<5, with: y)
edit: so, per your edit, to in-place zero out an array of any size in one go, you can do:
var x = [1.0,2.0,0.0]
// range to replace is the whole array's range,
// Repeat just generates any given value n times
x.replaceRange(indices(x), with: Repeat(count: x.count, repeatedValue: 0.0))
Adjust the range (and count of replacing entries) accordingly if you want to just zero out a subrange.
Given your example Point class, here is how you could implement this behavior assuming it's backed by an array under the hood:
struct Point<T: FloatLiteralConvertible> {
private var _vals: [T]
init(dimensions: Int) {
_vals = Array(count: dimensions, repeatedValue: 0.0)
}
mutating func replaceRange
<C : CollectionType where C.Generator.Element == T>
(subRange: Range<Array<T>.Index>, with newElements: C) {
// just forwarding on the request - you could perhaps
// do some additional validation first to ensure dimensions
// aren't being altered...
_vals.replaceRange(subRange, with: newElements)
}
}
var x = Point<Double>(dimensions:3)
x.replaceRange(0...2, with: [1.1,2.2,3.3])
You need to implement subscript(InvervalType) to handle the case of multiple assignments like this. That isn't done for you automatically.