The lowest initial numbers in a Fibonacci-like sequence

22

0

Given a positive integer input N, output the two non-negative numbers, a and b, where a < b, with the lowest possible mean value that will result in the number N being part of the recurring relation sequence:

f(0) = a
f(1) = b
f(n) = f(n-2)+f(n-1)

In case there are more than one solution where the mean of a and b are minimal, then you should output the one with the lowest b.

Your can assume N is within the representative range of integers in your language / system.

Test cases

N = 1
a = 0, b = 1

N = 15
a = 0, b = 3

N = 21
a = 0, b = 1

N = 27
a = 0, b = 9   <- Tricky test case. [3, 7] is not optimal and [4, 3] is not valid

N = 100
a = 4, b = 10

N = 101
a = 1, b = 12

N = 102
a = 0, b = 3

N = 1000
a = 2, b = 10

Stewie Griffin

Posted 2017-11-11T23:13:18.500

Reputation: 43 471

If a>=0 and a<b are there ever multiple solutions? – Jonathan Allan – 2017-11-12T00:09:11.017

I can't guarantee that there are or aren't multiple solutions. Both 1,4 and 2,3 would give 5, and they have the same mean. I guess it's possible to find cases similar to that one, where these are the lowest mean values. If you can show/prove that there aren't multiple solutions then you don't need to check for that condition. – Stewie Griffin – 2017-11-12T00:22:12.523

I checked up to 7457, and I didn't find any multiple solutions, although I haven't thought of any obvious proof. – Ørjan Johansen – 2017-11-12T02:12:00.133

2

totally inspired by https://codegolf.stackexchange.com/q/147200/67961

– J42161217 – 2017-11-12T02:28:11.573

... But certainly not a dupe. – user202729 – 2017-11-12T06:53:42.020

@ØrjanJohansen What do you means by "multiple solution"? Two pairs (a1, b1) and (a2, b2) such that a1+b1=a2+b2 and a1≠a2 and b1≠b2? – user202729 – 2017-11-12T06:55:35.370

@user202729 Yes, but still with minimal sum. – Ørjan Johansen – 2017-11-12T17:12:23.197

3

The corresponding OEIS sequence for the lowest possible mean, A249783, has a wild looking graph.

– Peter Kagey – 2017-11-12T19:20:33.873

1@ØrjanJohansen I added a proof to my answer that there are no duplicate solutions (since my answer depended on it). – cardboard_box – 2017-11-12T21:26:56.997

Answers

8

APL (Dyalog), 75 71 64 59 53 48 44 43 bytes

2 bytes saved thanks to @Adám

12 bytes saved thanks to @ngn

⊃o/⍨k∊¨+\∘⌽⍣{k≤⊃⍺}¨o←a/⍨</¨a←,⍉|-\¨⍳2⍴1+k←⎕

Try it online!

Uses ⎕IO←0.

How? This had gone real nuts.

k←⎕ - assign input to k

⍳2⍴1+k←⎕ - Cartesian product of the range 0 to k with itself

|-\¨ - substract each right pair element from the left, and get absolute values

a←,⍉ - transpose, flatten and assign to a

o←a/⍨</¨a - keep only pairs where the left element is smaller than the right, and assign to o

o now contains list of all pairs with a < b, ordered by their arithematical mean

+\∘⌽⍣{k≤⊃⍺}¨o - for each pair in o, apply fibonacci (reverse the pair and cumsum) until k or higher term is reached

k∊¨ - then decide if k is this last term (meaning it is contained in the sequence)

o/⍨ - and keep pairs in o where the previous check applies

- return the first result.

Uriel

Posted 2017-11-11T23:13:18.500

Reputation: 11 708

8

Husk, 19 18 16 14 13 15 bytes

Thanks Zgarb for saving 1 byte.

ḟö£⁰ƒẊ++ÖΣṖ2Θḣ⁰

Try it online!

Explanation:

Disclaimer: I really don't understand the ȯƒẊ++ section of the code.

Edit: It appears to translate to the Haskell fix.(mapad2(+).).(++), where mapad2 is apply function to all adjacent pairs in a list. (Although, knowing Husk, in the context of this program it could mean something else)

            Θḣ⁰    Create the list [0..input]
          Ṗ2       Generate all possible sublists of length 2
        ÖΣ         Sort them on their sums
ḟ                  Find the first element that satisfies the following predicate.
    ƒẊ++             Given [a,b], magically generate the infinite Fibonacci-like
                     sequence from [a,b] without [a,b] at the start.
 ö£⁰                 Is the input in that list (given that it is in sorted order)?

H.PWiz

Posted 2017-11-11T23:13:18.500

Reputation: 10 962

Save a byte with ö – Zgarb – 2017-11-12T09:44:41.680

I'm sure I tried that... – H.PWiz – 2017-11-12T12:55:20.230

8

JavaScript (Node.js), 92 90 89 91 83 82 bytes

-3 bytes -1 byte thanks to ThePirateBay

-8 -9 bytes thanks to Neil.

f=(n,a=1,b=0,c=(a,b)=>b<n?c(a+b,a):b>n)=>c(a,b)?b+2<a?f(n,a-1,b+1):f(n,b-~a):[b,a]

Try it online!

Note: this solution relies on the fact that there are never multiple minimal solutions.

Proof that there are never multiple solutions:

Let FIB(a,b,k) be the Fibonacci-like sequence starting with a,b:

FIB(a,b,0) = a
FIB(a,b,1) = b
FIB(a,b,k) = FIB(a,b,k-1) + FIB(a,b,k-2)

Lemma 1

The difference between Fibonacci-like sequences is itself Fibonacci-like, i.e. FIB(a1,b1,k) - FIB(a0,b0,k) = FIB(a1-a0,b1-b0,k). The proof is left to reader.

Lemma 2

For n >= 5, a solution a,b exists satisfying a+b < n:

if n is even, FIB(0,n/2,3) = n

if n is odd, FIB(1,(n-1)/2,3) = n

Proof

Cases where n < 5 can be checked exhaustively.

Suppose we have two minimal solutions for n >= 5, a0,b0 and a1,b1 with a0 + b0 = a1 + b1 and a0 != a1.

Then there exist k0,k1 such that FIB(a0,b0,k0) = FIB(a1,b1,k1) = n.

  • Case 1: k0 = k1

    WLOG assume b0 < b1 (and therefore a0 > a1)

    Let DIFF(k) be the difference between the Fibonnaci-like sequences starting with a1,b1 and a0,b0:

    DIFF(k) = FIB(a1,b1,k) - FIB(a0,b0,k) = FIB(a1-a0,b1-b0,k) (Lemma 1)

    DIFF(0) = a1 - a0 < 0

    DIFF(1) = b1 - b0 > 0

    DIFF(2) = (a1+b1) - (a0+b0) = 0

    DIFF(3) = DIFF(1) + DIFF(2) = DIFF(1) > 0

    DIFF(4) = DIFF(2) + DIFF(3) = DIFF(3) > 0

    Once a Fibonnaci-like sequence has 2 positive terms, all subsequent terms are positive.

    Thus, the only time DIFF(k) = 0 is when k = 2, so the only choice for k0 = k1 is 2.

    Therefore n = FIB(a0,b0,2) = a0 + b0 = a1 + b1

    The minimality of these solutions contradicts Lemma 2.

  • Case 2: k0 != k1:

    WLOG assume k0 < k1.

    We have FIB(a1,b1,k1) = n

    Let a2 = FIB(a1,b1,k1-k0)

    Let b2 = FIB(a1,b1,k1-k0+1)

    Then FIB(a2,b2,k0) = FIB(a1,b1,k1) = FIB(a0,b0,k0) (exercise for the reader)

    Since FIB(a1,b1,k) is non-negative for k >= 0, it is also non-decreasing.

    This gives us a2 >= b1 > a0 and b2 >= a1+b1 = a0+b0.

    Then let DIFF(k) = FIB(a2,b2,k) - FIB(a0,b0,k) = FIB(a2-a0,b2-b0,k) (Lemma 1)

    DIFF(0) = a2 - a0 > 0

    DIFF(1) = b2 - b0 >= (a0 + b0) - b0 = a0 >= 0

    DIFF(2) = DIFF(0) + DIFF(1) >= DIFF(0) > 0

    DIFF(3) = DIFF(1) + DIFF(2) >= DIFF(2) > 0

    Once again, DIFF has 2 positive terms and therefore all subsequent terms are positive.

    Thus, the only time when it's possible that DIFF(k) = 0 is k = 1, so the only choice for k0 is 1.

    FIB(a0,b0,1) = n

    b0 = n

    This contradicts Lemma 2.

cardboard_box

Posted 2017-11-11T23:13:18.500

Reputation: 5 150

189 bytes – None – 2017-11-12T00:35:57.917

177 bytes – Neil – 2017-11-12T10:19:26.333

@Neil That minimizes b instead of minimizing a+b, and thus your solution gives f(27) = [3,7] but the optimal solution is f(27)=[0,9]. After reverting the breaking changes we're down to 83 bytes. – cardboard_box – 2017-11-12T18:20:38.623

1I think you can save another byte by using b-~a instead of a+b+1. – Neil – 2017-11-13T00:01:15.770

1There's a small error in your second case: a2 >= a1 + b1 isn't correct when k1-k0=1. Instead you can use a2 >= b1 > a0 and b2 >= a1+b1 = a0+b0, and then the rest follows. – Ørjan Johansen – 2017-11-13T02:48:57.193

@ØrjanJohansen Thanks. Should be fixed now. – cardboard_box – 2017-11-13T02:57:11.140

8

Haskell, 76 72 74 bytes

EDIT:

  • -4 bytes: @H.PWiz suggested using / instead of div, although this requires using a fractional number type.
  • +2 bytes: Fixed a bug with Enum ranges by adding -1.

f takes a value of Double or Rational type and returns a tuple of same. Double should suffice for all values that are not large enough to cause rounding errors, while Rational is theoretically unlimited.

f n|let a?b=b==n||b<n&&b?(a+b)=[(a,s-a)|s<-[1..],a<-[0..s/2-1],a?(s-a)]!!0

Try it online! (with H.PWiz's header adjustments to input/output Rationals in integer format)

How it works

  • ? is a locally nested operator in the scope of f. a?b recursively steps through the Fibonacci-like sequence starting with a,b until b>=n, returning True iff it hits n exactly.
  • In the list comprehension:
    • s iterates through all numbers from 1 upwards, representing the sum of a and b.
    • a iterates through the numbers from 0 to s/2-1. (If s is odd the end of range rounds up.)
    • a?(s-a) tests if the sequence starting with a,s-a hits n. If so, the list comprehension includes the tuple (a,s-a). (That is, b=s-a, although it was too short to be worth naming.)
    • !!0 selects the first element (hit) in the comprehension.

Ørjan Johansen

Posted 2017-11-11T23:13:18.500

Reputation: 6 914

5

Python 2, 127 109 107 bytes

-2 bytes thanks to ovs (changing and to *)

g=lambda x,a,b:a<=b<x and g(x,b,a+b)or b==x
f=lambda n,s=1,a=0:g(n,a,s-a)*(a,s-a)or f(n,s+(a==s),a%s+(a<s))

Try it online!

Any bonus points for n,a,s-a?

Explanation:

  • The first line declares a recursive lambda, g, which verifies whether a, b expanded as a Fibonacci sequence will reach x. It also checks that a <= b, one of the criteria of the question. (This would allow cases where a == b, but in such a case 0, a would have already been discovered and returned).
    • The chained inequality a<=b<x performs two handy tasks at once: verifying a <= b, and that b < x.
    • If b < x yields True, the function calls itself again with the next two numbers in the Fibonacci sequence: b, a+b. This means the function will keep working out new terms until...
    • If b < x yields False, then we have reached the point where we need to check if b==x. If so, this will return True, signifying that the initial pair a, b will eventually reach x. Otherwise, if b > x, the pair is invalid.
  • The second line declares another recursive lambda, f, which finds the solution for a given value n. It recursively tries new initial pairs, a, b, until g(n, a, b) yields True. This solution is then returned.
    • The function recursively counts up initial Fibonacci pairs using two variables, s (initially 1) and a (initially 0). On each iteration, a is incremented, and a, s-a is used as the first pair. However, when a hits s, it is reset back to 0, and s is incremented. This means the pairs are counted up in the following pattern:
      s=1 (0, 1) (1, 0)
      s=2 (0, 2) (1, 1)  (2, 0)
      s=3 (0, 3) (1, 2), (2, 1), (3, 0)
      
      Obviously, this contains some invalid pairs, however these are eliminated instantly when passed to g (see first bullet point).
    • When values a and s are found such that g(n, a, s-a) == True, then this value is returned. As the possible solutions are counted up in order of 'size' (sorted by mean, then min value), the first solution found will always be the smallest, as the challenge requests.

FlipTack

Posted 2017-11-11T23:13:18.500

Reputation: 13 242

3

R, 183 bytes 160 bytes

n=scan();e=expand.grid(n:0,n:0);e=e[e[,2]>e[,1],];r=e[mapply(h<-function(n,a,b,r=a+b)switch(sign(n-r)+2,F,T,h(n,b,r)),n,e[,1],e[,2]),];r[which.min(rowSums(r)),]

Try it online!

Thanks to Giuseppe for golfing off 23 bytes

Code explanation

n=scan()                        #STDIO input
e=expand.grid(n:0,n:0)          #full outer join of integer vector n to 0
e=e[e[,2]>e[,1],]               #filter so b > a
r=e[mapply(
  h<-function(n,a,b,r=a+b)switch(sign(n-r)+2,F,T,h(n,b,r)),
                                #create a named recursive function mid-call 
                                #(requires using <- vs = to denote local variable creation 
                                #rather than argument assignment
  n,e[,1],e[,2]),]              #map n, a and b to h() which returns a logical
                                #which is used to filter the possibilities
r[which.min(rowSums(r)),]       #calculate sum for each possibility, 
                                #get index of the minimum and return
                                #because each possibility has 2 values, the mean and 
                                #sum will sort identically.

Mark

Posted 2017-11-11T23:13:18.500

Reputation: 411

1160 bytes -- in general, you should save bytes wherever you can, so saving 4 bytes by removing nice naming is not only acceptable or encouraged but in some sense required by [tag:code-golf]. Even so, nice answer, +1. – Giuseppe – 2017-11-12T13:14:03.177

1

Jelly, 19 bytes

ṫ-Sṭµ¡³e
0rŒcÇÐfSÐṂ

Try it online!

-1 byte thanks to the proof by cardboard_box. In case it's disproved, you can append UṂṚ to the end of the second line for 22 bytes in total.

Erik the Outgolfer

Posted 2017-11-11T23:13:18.500

Reputation: 38 134

...a leading increment should resolve @StewieGriffin's observation. – Jonathan Allan – 2017-11-11T23:53:30.567

I have a feeling you can drop the

– Jonathan Allan – 2017-11-12T00:11:18.657

1We only need to find the seed that makes the input, x, appear latest. If x were found at the third index for multiple then it works for 0,x and would therefore also work at either 1,(x-1)/2 (x odd) or 2,x/2-1 (x even) whereupon x would appear later in the result, so that wont happen. For a later collision the mean can only be the same if the third terms are the same too, but then one must have a lower difference between the initial terms (else they'd be the same) and hence will have x found at a later index. As such we can do ṫ-Sṭµ¡i³¶ḶŒcÇÐṀ saving four bytes. – Jonathan Allan – 2017-11-12T02:33:49.433

...oops, plus the increment: ṫ-Sṭµ¡i³¶‘ḶŒcÇÐṀ

– Jonathan Allan – 2017-11-12T02:45:45.730

@StewieGriffin That test-case didn't exist when I answered :p – Erik the Outgolfer – 2017-11-12T11:08:24.633

@JonathanAllan In case there are more than one solution then you should output the one with the lowest maximum value. That means I must add bytes! D: time to find a proof EDIT: looks like you've got something that doesn't need the proof... – Erik the Outgolfer – 2017-11-12T11:12:51.230

The test case didn't exist, but the possibility of such an input did ;-) – Stewie Griffin – 2017-11-12T12:28:32.890

@StewieGriffin And my tiredness also did ;-P – Erik the Outgolfer – 2017-11-12T12:36:04.600

@JonathanAllan Looks like your version was invalid :/ – Erik the Outgolfer – 2017-11-12T21:43:34.580

Why so? Maybe deleted comments? – Jonathan Allan – 2017-11-12T22:33:39.823

@JonathanAllan Your version outputs [[0, 9], [3, 7]] on input 27. – cardboard_box – 2017-11-12T22:40:36.537

@cardboard_box thanks I see! Could add SÐṂ for 19 though I suppose (or remove the from Erik's, due to your proof). – Jonathan Allan – 2017-11-12T22:53:57.167

... in fact the could stay and you could still have 19 with ...ÐfSÞḢ – Jonathan Allan – 2017-11-12T23:02:02.967

@JonathanAllan I don't think that works (sort by sum and take the head? looks like that's getting the lowest minimum). In fact, I think I need a 22-byter where I replace with UṂṚ. – Erik the Outgolfer – 2017-11-13T12:26:42.573

True dat. (+6.) – Jonathan Allan – 2017-11-13T15:52:08.330

1

Mathematica, 117 bytes

If[#==1,{0,1},#&@@SortBy[(S=Select)[S[Range[0,s=#]~Tuples~2,Less@@#&],!FreeQ[LinearRecurrence[{1,1},#,s],s]&],Mean]]&


Try it online!

J42161217

Posted 2017-11-11T23:13:18.500

Reputation: 15 931

1

GolfScript - 88 77 bytes

~:N[,{1+:a,{[.;a]}/}/][{[.~{.N<}{.@+}while\;N=]}/]{)1=\;},{(\;~+}$(\;);~~' '\

I did not check for multiple solutions, thanks to cardboard_box!

Explanation

~:N                           # Reads input
[,{1+:a,{[.;a]}/}/]           # Creates an array of pairs [a b]
[{[.~{.N<}{.@+}while\;N=]}/]  # Compute solutions
{)1=\;},         # Pairs that are not solutions are discarded
{(\;~+}$         # Sorts by mean
(\;);~~' '\      # Formats output

FedeWar

Posted 2017-11-11T23:13:18.500

Reputation: 271

Try it online! – Ørjan Johansen – 2017-11-14T00:16:42.197

0

Batch, 160 158 bytes

@set/aa=b=0
:g
@if %a% geq %b% set/ab-=~a,a=0
@set/ac=a,d=b
:l
@if %c% lss %1 set/ad+=c,c=d-c&goto l
@if %c% gtr %1 set/aa+=1,b-=1&goto g
@echo %a% %b%

Neil

Posted 2017-11-11T23:13:18.500

Reputation: 95 035

This (also) gives 3 7 on input 27. The correct solution is 0 9. – cardboard_box – 2017-11-12T22:10:47.627

@cardboard_box Still not seeing where the question requires that... – Neil – 2017-11-12T22:48:00.597

In the first sentence: "with the lowest possible mean value". – cardboard_box – 2017-11-12T22:52:35.460

@cardboard_box Ah, sorry, that was too easy to overlook. – Neil – 2017-11-12T23:34:49.907

1@cardboard_box OK should be fixed now. – Neil – 2017-11-13T00:01:31.760