0

I am learning Mathematica because I love it. I also love solving puzzles so I think it would be a nice way to learn Mathematica through puzzles. This is the second puzzle in a series I intend to solve. The first puzzle is here.

A shopkeeper has five weights to weigh things and he can weigh anything from 1 to 121 accurately (integers only) can. How do you write a program that finds those weights?

Example: The shopkeeper can weigh up to four kilos with a one-kilo weight and a three-kilo weight. If he'd put the one-kilo weight and the three-kilo weight on different sides of the scale, he could measure two kilos worth of goods. If he'd put both of the weights on the same side he can measure four kilos worth of goods.

The name of the puzzle is a pun, not a good one though as I primarily intended the shopkeeper to weight 40KG only.


Question was inspired by this question: How do I generate a set of n-tuples containing integral solutions to a linear equation provided certain constraints?

Jawad_Mansoor
  • 321
  • 1
  • 9
  • 3
    Notice that this question isn't really on topic as this site isn't about solving abstract puzzles but about e.g. implementation of solutions in Mathematica. Though the community is very forgiving when it comes to interesting questions. Just don't be surprised if next time you will get "what have you done / this is off topic here" comments :) Even this question may end up being closed if it won't receive much attention. – Kuba Feb 26 '17 at 11:57
  • 2
    Solution on Puzzling.SE: http://puzzling.stackexchange.com/q/186 (spoiler, obviously) – Mr.Wizard Feb 26 '17 at 12:03
  • @Mr.Wizard I know how it is done on paper. But I want to LEARN Mathematica that is why I asked this question. Otherwise I would not even bother typing a sentence that would be waste of my time. – Jawad_Mansoor Feb 26 '17 at 12:06
  • 3
    I am honestly not sure what you are seeking. Typically one would develop an "on paper" solution and then implement an algorithm in programming, but here there is little to implement unless one wishes to prove the solution by brute force. What kind of input are you hoping to give Mathematica for a puzzle like this? – Mr.Wizard Feb 26 '17 at 12:09
  • @Mr.Wizard Now that you asked, I am not so sure myself. However I thought computer would just go utilize its brute force (checking all answers and coming up with the right solution). That was my idea. However, you are right the algorithm makes things much easy and are done at first on paper.

    Well, I want as many syntax as there are (unless they are too many, in that case the popular ones only) to solve such questions. 1> Brute force and second the algorithm proposed in the -[Link]puzzle.stackexchange.com.

    That is only because I want to Learn Mathematica.

    – Jawad_Mansoor Feb 26 '17 at 12:14
  • @Kuba I am just trying to Learn Mathematica. I am grateful for being here, I am grateful of StockExchange and everyone involved, grateful to Mathematica community and all those who promptly comment. I am specially grateful to those who helped me learn me a lot in short time (in just few hours) I learnt commands/functions that I struggled with before. Don't you think there would be others like me who want to learn. As I saw a guy commenting who did not that IntegerPartition could be used to formulate an answer. – Jawad_Mansoor Feb 26 '17 at 12:20
  • Just reply with syntax that solves this through brute force! – Jawad_Mansoor Feb 26 '17 at 12:25
  • I am not sure this is Mathematica though it could be implemented ( I am off to sleep ) but 1,3,9,27,81: allows weighing 1 to 121: e.g. 7 =9+1-3 etc – ubpdqn Feb 26 '17 at 12:29
  • @ubpdqn that is right, but it is just the answer, the solution. I want syntax so that I can understand Mathematica better. – Jawad_Mansoor Feb 26 '17 at 12:39
  • Yes, @Kuba it is about solving a problem IN MATHEMATICA. I know how to ...

    Okay, let me write the algorithm for you just to show you that I understand how it works.

    1

    1,3 1,3,9 1,3,9,27 1,3,9,27,81 1,3,9,27,81...

    These all are multiple of 3 and will yield

    1

    4 13 40 81

    and so on

    That is how I did it on paper but now I want to learn a formula, syntax, program or something that uses brute force (which I call iteration) to get the answer by going through all possible combinations of numbers from 1 to 30 or 40. All positive integers.

    – Jawad_Mansoor Feb 26 '17 at 12:48
  • @Jawad I think I understand what you want. Give me a few minutes to cook something up. Nevertheless this is not a pattern for long term success. – Mr.Wizard Feb 26 '17 at 12:49
  • 1
    @Kuba I have to agree with you. This site is about what you have tried and how can something be possibly done, if what you have tried is not working. Any question statement of this sort is not in the spirit of the site. And as Mr.Wizard pointed this pattern of posing question statements will not help you to either evolve at solving puzzles or with the Mathematica way of programming itself. What will help is if you try yourself. – Ali Hashmi Feb 26 '17 at 13:42
  • @AliHashmi I do try different things. I change number of variables or values or something to learn. My way is natural way of learning. It is like when neural network first learn of its existence, body moves, feels and gather data from environment. That is how I learn instead of directly programming the brain i.e. reading text. But of course I do read text to get understanding of the nature/environment/code/program later on. – Jawad_Mansoor Feb 26 '17 at 16:12
  • @Mr.Wizard BTW was "scales as needed" an intended pun?I enjoyed it and the answer. For your amusement. – ubpdqn Feb 27 '17 at 07:56
  • @ubpdqn thanks man. That was fun. – Jawad_Mansoor Feb 27 '17 at 11:49
  • 1
    @ubpdqn Sadly no, I was not sharp enough to realize the pun as I wrote it. My choice of words was probably subconsciously influenced by the context. – Mr.Wizard Feb 27 '17 at 13:22

2 Answers2

4

Here is an example of brute forcing this problem through enumeration and numerical optimization.

OK, I realize my example was unnecessarily brute; I could at least order and bound the terms.

ClearAll[enum, count, a, b, c, d, e];

enum[s_] := Tr /@ Tuples @ Thread[{-s, 0, s}] // Abs // Union

mem : count[w__Integer] := mem = LengthWhile[Differences @ enum @ {w}, # == 1 &]

NMaximize[
  {count[a, b, c, d, e], 1 <= a <= b <= c <= d <= e <= 121},
  {a, b, c, d, e},
  Integers
  , MaxIterations -> 1000
] // AbsoluteTiming
{7.75791, {121., {a -> 1, b -> 3, c -> 9, d -> 27, e -> 81}}}

You remarked about saving time. That's not really how brute force works. There is probably a way to tune the search but it's not how I would approach the problem. Instead solve smaller examples and look for a pattern.

NMaximize[{count[a, b], 1 <= a <= b <= 121}, {a, b}, Integers, 
 MaxIterations -> 1000]

NMaximize[{count[a, b, c], 1 <= a <= b <= c <= 121}, {a, b, c}, Integers, 
 MaxIterations -> 1000]

NMaximize[{count[a, b, c, d], 1 <= a <= b <= c <= d <= 121}, {a, b, c, d}, Integers, 
 MaxIterations -> 1000]
{4., {a -> 1, b -> 3}}

{13., {a -> 1, b -> 3, c -> 9}}

{40., {a -> 1, b -> 3, c -> 9, d -> 27}}

That should be enough to implement an intelligent solution that scales as needed.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Wow, it almost took a minute to compute the answer. @mr.wizard you are not God but you sure are saviour. – Jawad_Mansoor Feb 26 '17 at 13:01
  • Is there something that can save time as well? It almost took a minute on my core two 2.7+ghz – Jawad_Mansoor Feb 26 '17 at 13:01
  • @Jawad_Mansoor Hey like it said it is brute force; no intelligence behind the design, just figure out all sums and count them up. I am glad you found this satisfying, and hopefully you find it possible to learn from this example as well. – Mr.Wizard Feb 26 '17 at 13:03
  • I have learnt a lot in very short time. Thanks to all the supportive people on the community. And it is so interesting all the same time. I will learn elements in your answer above as well, and try to understand them if I can't I will either ask a new question or comment again.

    Thanks again.

    – Jawad_Mansoor Feb 26 '17 at 13:06
  • @Mr.Wizard thanks for a clear approach and the update with constraint. The ternary representation seemed the natural solution with the 121 as a hint ((243-1)/2)... – ubpdqn Feb 26 '17 at 14:02
  • 1
    Apologizing for the ruckus I created yesterday which could have been avoided if had been careful in coding.

    Mr. Wizard's code to use brute-force is hundred 100# accurate and working but the any of the lines

    `NMaximize[{count[a, b], 1 <= a <= b <= 121}, {a, b}, Integers, MaxIterations -> 1000]

    NMaximize[{count[a, b, c], 1 <= a <= b <= c <= 121}, {a, b, c}, Integers, MaxIterations -> 1000]

    NMaximize[{count[a, b, c, d], 1 <= a <= b <= c <= d <= 121}, {a, b, c, d}, Integers, MaxIterations -> 1000]`

    would not work alone you need to define enum and count first.

    – Jawad_Mansoor Feb 27 '17 at 11:46
4

This is verification of answer: I will type code in am:

(*the weights*)
r = PowerRange[81, 1, 1/3];  
(*generate possible positive weighings*)
tu[n_] := Cases[Tuples[{-1, 0, 1}, n], {1, ___}]
w = PadLeft[Catenate[tu /@ Range[5]]];
(*the weighings and the sum*)
ans = {##, Style[{##}.r, Red, Bold]} & @@@ w;
(*presentation*)
tf = TableForm[#, TableHeadings -> {None, r~Join~{"Sum"}}] & /@ 
   Partition[ans, 11];
Grid[Partition[tf~Join~{""}, 4]]

enter image description here

ubpdqn
  • 60,617
  • 3
  • 59
  • 148
  • Hää? Mathematica on Android?? – LLlAMnYP Feb 26 '17 at 15:12
  • @ubpdqn That is complicated for a newbie like me. However the grid in the end, man that is marvelous. Not only I am accepting your answer but also giving you a rate up because you have gone length to get the answer. I am extremely thankful as this is going to really help me in learning new commands. One problem however is that it does not begin with 1 in my computer as yours here. – Jawad_Mansoor Feb 26 '17 at 16:37
  • @LLlAMnYP Wolfram Cloud on iPhone: glitchy in my experience – ubpdqn Feb 26 '17 at 23:21
  • @Jawad_Mansoor This is just a verification of proposed solution. Ternay numbers natural fit: all numbers are-1,0,1 from a multiple of 3. So, Tuples just produces possible arrangements of weighings using specified weights.Cases selects postive ones. The rest is window dressing.The best way I have learned Mathematica is to play. Good luck :) – ubpdqn Feb 26 '17 at 23:25
  • @ubpdqn thanks man that was beautiful. :)

    By the way can you tell me what was the problem in the old code which prevented it to begin from 1 (it started from 2)

    tu[n_] := Cases[Tuples[{-1, 0, 1}, n], {1, __}] r = PowerRange[1, 81, 3] p = tu /@ Range[5]; pad = PadLeft[Catenate[p]]; res = {##, {##}.Reverse[r]} & @@@ pad; TableForm[res]

    – Jawad_Mansoor Feb 27 '17 at 03:46
  • @Jawad_Mansoor tu[n_] := Cases[Tuples[{-1, 0, 1}, n], {1, ___}] r = PowerRange[1, 81, 3] p = tu /@ Range[5]; pad = PadLeft[Catenate[p]]; res = {##, {##}.Reverse[r]} & @@@ pad; TableForm[res] should work. Note the added underscore in patten for Cases. My answer is only verficiation for the proposed solution. @Mr.Wizard provides an algorithm to try to solve and I voted for his answer as it illustrates a lot.Good luck :) – ubpdqn Feb 27 '17 at 04:37