Group Abstract Group Abstract

Message Boards Message Boards

1
|
12.7K Views
|
17 Replies
|
17 Total Likes
View groups...
Share
Share this post:

Sort pairs that add up to a perfect square?

POSTED BY: Ashley Louk
17 Replies

Any suggestions on what I can replace CirclePoints and Association with? They are also mathematica 10 commands. I guess I really do need to hassle the IT department for an upgrade.

POSTED BY: Ashley Louk

CirclePoints can be changed to circlepoints:

circlepoints[{x_, y_}, {r_, \[Theta]_}, n_Integer] := 
 Table[{x + r Cos[t + \[Theta]], y + r Sin[t + \[Theta]]}, {t, 
   Most@Range[0, 2 Pi, 2 Pi/n]}]
POSTED BY: Sander Huisman

And Association can be avoided by replacing the two consecutive lines as follows:

lines = Thread[numbers -> pos];
lines = Map[# /. lines &, sol, {2}];
POSTED BY: Sander Huisman
POSTED BY: Ashley Louk

SelectFirst

Was introduced in version 10. So that explains it. You can replace it indeed by the code you mentioned or define a SelectFirst yourself... note that the built-in is a bit more efficient; it will stop 'selecting' after finding the first one, where as yours will 'select' all of them first...

Good luck

POSTED BY: Sander Huisman

Wow. That's impressive. Thanks for all your help.

POSTED BY: Ashley Louk

I further updated the code to be more smart for large n:

$HistoryLength = 1;
ClearAll[DividePerfectSquarePairs, DividePerfectSquarePairsRecurse, SquareQ, PureQ, VisualizePairs]
SquareQ[n_Integer] := SquareQ[n] = IntegerQ[Sqrt[n]]
PureQ[l_List] := (l === Range[1, Length[l]])
DividePerfectSquarePairsRecurse[pairs_List, left_List] := Module[{cand, n, t, newpairs},
  If[PureQ[left] \[And] Length[left] >= 62,
   n = Length[left];
   t = SelectFirst[Range[n], SquareQ[# + n] \[And] OddQ[#] \[And] # >= 25 &];
   newpairs = {Range[t, t + ((n - t) - 1)/2], Reverse@Range[t + ((n - t) - 1)/2 + 1, n]};
   DividePerfectSquarePairsRecurse[Join[Transpose[newpairs], pairs], Range[t - 1]]
   ,
   If[Length[left] > 2,
    Do[cand = {left[[1]], left[[i]]};
     If[SquareQ[Total[cand]],
      DividePerfectSquarePairsRecurse[Append[pairs, cand], 
       Delete[left, {{1}, {i}}]]
      ]
     ,
     {i, 2, Length[left]}
     ]
    ,
    If[SquareQ[Total[left]],
     Throw[Append[pairs, left]];
     ]
    ]
   ]
  ]
DividePerfectSquarePairs[n_Integer?EvenQ] := Module[{},
  If[SquareQ[n + 1],
   Transpose[{Range[1, n/2], Range[n, n/2 + 1, -1]}]
   ,
   Catch[DividePerfectSquarePairsRecurse[{}, Range[n]]; Missing[]]
   ]
  ]
DividePerfectSquarePairs[n_Integer?OddQ] := Missing[]
VisualizePairs[sol : {{_Integer, _Integer} ..}] := 
 Module[{numbers, len, pos, angles, txts, lines, colors},
  numbers = Union @@ sol;
  colors = ColorData[109] /@ (Sqrt[Total[sol, {2}]] - 1);
  len = Length[numbers];
  pos = Reverse[CirclePoints[{0.0, 0.0}, {1.5, \[Pi]/2 + \[Pi]/len}, len]];
  angles = If[#1 < 0, -{##}, {##}] & @@@ pos;
  txts = MapThread[Text[#1, #2, {0, 0}, #3] &, {numbers, pos, angles}];
  lines = Association[Thread[numbers -> pos]];
  lines = Map[lines, sol, {2}];
  lines = 0.9 {#1, {0, 0}, #2} & @@@ lines;
  Graphics[{txts, Thick, Riffle[colors, BezierCurve /@ lines]}, ImageSize -> 300, PlotRange -> 1.6]
 ]

It can now easily handle n=1000 or even much much bigger (for fun I tried 10^6 and it found the solution in ~19 seconds). It does so by finding a low m (but not too low) such that m....a and a+1 ... n can form pairs that form squares. This reduces then the problem from finding a solution for n, to finding a solution for m-1 (because m...n are 'eliminated').

So now one can type in:

VisualizePairs[DividePerfectSquarePairs[250]]

and quickly get the visual:

enter image description here

Notice that the problem is quickly reduced to a problem for n = 38. For which we use the old method. One could hard-code the solution for n=2...60 and then this function will be nearly instantaneous for all n (except those that can't be split up).

POSTED BY: Sander Huisman

A nice way to visualize is as follows:

VisualizePairs[sol : {{_Integer, _Integer} ..}] := Module[{numbers, len, pos, angles, txts, lines, colors},
  numbers = Union @@ sol;
  colors = ColorData[109] /@ (Sqrt[Total[sol, {2}]] - 1);
  len = Length[numbers];
  pos = Reverse[CirclePoints[{0.0, 0.0}, {1.5, \[Pi]/2 + \[Pi]/len}, len]];
  angles = If[#1 < 0, -{##}, {##}] & @@@ pos;
  txts = MapThread[Text[#1, #2, {0, 0}, #3] &, {numbers, pos, angles}];
  lines = Association[Thread[numbers -> pos]];
  lines = Map[lines, sol, {2}];
  lines = 0.9 {#1, {0, 0}, #2} & @@@ lines;
  Graphics[{txts, Thick, Riffle[colors, BezierCurve /@ lines]}, ImageSize -> 300, PlotRange -> 1.6]
  ]

We can now generate some test:

Partition[
  VisualizePairs[DividePerfectSquarePairs[#]] & /@ 
   DeleteCases[Range[8, 46, 2], 10 | 12 | 20 | 22], UpTo[2]] // Grid

giving:

enter image description here

POSTED BY: Sander Huisman
POSTED BY: Sander Huisman
POSTED BY: Ashley Louk

It can be slightly improved because some of them can be easily solved:

$HistoryLength = 1;
ClearAll[DividePerfectSquarePairs, DividePerfectSquarePairsRecurse, SquareQ]
SquareQ[n_Integer] := SquareQ[n] = IntegerQ[Sqrt[n]]
DividePerfectSquarePairsRecurse[pairs_List, left_List] := Module[{cand},
  If[Length[left] > 2,
   Do[
    cand = {left[[1]], left[[i]]};
    If[SquareQ[Total[cand]],
     DividePerfectSquarePairsRecurse[Append[pairs, cand], Delete[left, {{1}, {i}}]]
     ]
    ,
    {i, 2, Length[left]}
    ]
   ,
   If[SquareQ[Total[left]],
    Throw[Append[pairs, left]];
    ]
   ]
  ]
DividePerfectSquarePairs[n_Integer?EvenQ] := Module[{},
  If[SquareQ[n + 1],
   Transpose[{Range[1, n/2], Range[n, n/2 + 1, -1]}]
   ,
   Catch[DividePerfectSquarePairsRecurse[{}, Range[n]]; Missing[]]
   ]
  ]
DividePerfectSquarePairs[n_Integer?OddQ] := Missing[]
POSTED BY: Sander Huisman

So this code accounts for what I think of as zipper sets, where n is one less than a perfect square, to the set can be paired (1,n),(1,n-1),etc.

POSTED BY: Ashley Louk

Correct!

POSTED BY: Sander Huisman
Posted 9 years ago

Something I am doing wrong, since I still have numbers repeated at the beginning of each tuple, please take a look, thanks in advance.

Here is my code

mere[n_Integer] := 
 Module[{perm, squared, novo, rec}, 
  perm = Permutations[Range[n], {2}]; squared = Range[100]^2; 
  novo = Select[perm, #[[1]] < #[[2]] &];
  rec = DeleteCases[If[MemberQ[squared, Total[#]], #] & /@ novo, 
    Null]; Select[rec, Total[#] >= n &]]

See my results

errors obteined

Any help is welcoming ....

POSTED BY: Luis Ledesma

How can your method have a solution to 35? The numbers 1..35 can not be divided in two pairs; it is an odd number?

POSTED BY: Sander Huisman
POSTED BY: Ashley Louk
Posted 9 years ago

What would the answer for 16 be? If all the pairs have to add up to the same square, at least any odd square minus one would work, so for example the list {1, 2, ..., 24} gives you {{1, 24}, {2, 23}, ..., {12, 13}}, all adding to 25.

POSTED BY: Robert Dickau
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard