prolog - not a function warning - prolog

I have this Prolog program where I want to match players with players with the same level (newbie, intermediate, or expert) and server:
player(player29, 408, 183, europe).
player(player30, 462, 97, north-america).
player(player31, 25, 22, asia).
player(player32, 481, 248, asia).
player(player33, 111, 37, asia).
player(player34, 424, 359, north-america).
player(player35, 381, 358, asia).
player(player36, 231, 159, africa).
player(player37, 31, 20, africa).
player(player38, 22, 21, africa).
player(player39, 144, 35, oceania).
player(player40, 30, 25, asia).
player(player41, 221, 112, south-america).
player(player42, 344, 292, africa).
player(player43, 183, 148, asia).
player(player44, 62, 40, africa).
player(player45, 281, 23, north-america).
player(player46, 308, 173, south-america).
player(player47, 127, 125, asia).
player(player48, 441, 393, south-america).
player(player49, 213, 48, oceania).
player(player50, 343, 145, africa).
winrate(X):-player(X, T, W, _); (W/T) * 100.
newbie(X):-winrate(X) < 40.
intermediate(X):-winrate(X) >=40; winrate(X) < 80.
expert(X):-winrate(X) > 80.
However, I get a warning saying "Arithmetic: 'winrate(_G1082)' is not a function" when I compile it. Can someone explain to me what that means?

If I could nominate a misconception in Prolog for greatest all-time beginner stumbling block, it would be this: there is no such thing as a return value in Prolog. So the problem comes down to this definition:
winrate(X) :- player(X, T, W, _); (W/T) * 100.
If you type just that into Prolog, you'll get a mysterious looking warning message:
Warning: user://1:9:
Singleton variable in branch: T
Singleton variable in branch: W
I suspect you think that clause says "Look up T and W for player X and return W/T * 100." What Prolog actually thinks you said there is "Look up T and W for player X, or something over something times one hundred <awkward pause>" which is not particularly meaningful. When you ask winrate(player47), Prolog will stand in the corner with its hands in its pockets and say "um, true?"
The correction is this:
winrate(X, Rate) :- player(X, T, W, _), Rate is (W/T) * 100.
You have the exact same problem a little further down in newbie/1 et. al.: winrate(X) < 40 does not have intrinsic meaning in Prolog, because there is no "return value" in Prolog. The corrected expression is winrate(X, WinRate), WinRate < 40.
Note that there is nothing special about the last argument in Prolog. It's common for predicates with one-way semantics to use the last arguments for results, but it isn't really a law and Prolog is not enforcing anything there.
Pay close attention to singleton variable errors. Nothing meaningful happens in Prolog without variables appearing more than once, so if you get this error and you immediately replace the named variables with _, does your clause still seem to have enough information to do its work? If not, you have almost certainly missed something or are confused about Prolog's semantics. Believe me, I learned this one from experience.

Related

Search algorithm with best Time Complexity [duplicate]

This question already has answers here:
How do I search for a number in a 2d array sorted left to right and top to bottom?
(21 answers)
Closed 4 years ago.
Given the following data:
[4]
[5, 8]
[9, 12, 20]
[10, 15, 23, 28]
[14, 19, 31, 36, 48]
[15, 22, 34, 41, 53, 60]
[19, 26, 42, 49, 65, 72, 88]
[20, 29, 45, 54, 70, 79, 95, 104]
[24, 33, 53, 62, 82, 91, 111, 120, 140]
[25, 36, 56, 67, 87, 98, 118, 129, 149, 160]
[29, 40, 64, 75, 99, 110, 134, 145, 169, 180, 204]
[30, 43, 67, 80, 104, 117, 141, 154, 178, 191, 215, 228]
[34, 47, 75, 88, 116, 129, 157, 170, 198, 211, 239, 252, 280]
[35, 50, 78, 93, 121, 136, 164, 179, 207, 222, 250, 265, 293, 308]
[Etc.]
What could be the best searching algorithm with the most optimal Time Complexity for finding a given number?
The rows are sorted
The columns are sorted
A number may occur more than once
Extra info:
Suppose we are looking for the number 26:
Due to order, this means we can eliminate the first 3 rows and the remaining columns to the right.
Due to order, this also means we can ignore every row after row=11.
Which results to this:
[10, 15, 23]
[14, 19, 31]
[15, 22, 34]
[19, 26, 42]
[20, 29, 45]
[24, 33, 53]
[25, 36, 56]
[29, 40, 64]
My current algorithm has a time complexity of O(x log(y)) where x is the amount of columns and y is the size for the Binary Search algorithm for each column.
I'm looking for something faster because I'm dealing with huge amount of data.
Currently I'm using BST on every column, but could I use BST on rows aswell? maybe achieving a O(log(x) log(y))?
It can be done in O(x)
Let's call the element we are trying to find n
Start with the bottom left element.
For each element we search through (let's call it e):
if e == n: we found it
if e < n: move to the right
Justification:
All elements to the left of e, including the column that e is in, are less than e. Those elements cannot == n and can be eliminated.
if e > n: move up
Justification:
All elements below e are greater than e and can be eliminated. What about the values less than e to the left of e? Can't those be == n? No. For e to make those moves to the right and have values to it's left, those values would have been already eliminated in step 2
Repeat until n found or index out of bounds in which case such an element does not exist.
Time complexity:
The worst case scenario is if the element isn't in the array and we have an index out of bounds. This occurs at the main diagonal and the total distance to the right and total distance up to any element on the long diagonal always sums to x.
You can find the bottom left of your trimmed array with a binary search of the first column, and the top right with a binary search of the last column of each row.
From there, the problem degenerates to How do I search for a number in a 2d array sorted left to right and top to bottom? which is well-studied in the linked question. The best algorithm is dependent on the shape of the result.

Prolog: Reverse function of string_to_list

I know the Prolog-builtin "string_to_list". Now i need to reverse its functionality.
?- string_to_list('a*1+2', L).
L = [97, 42, 49, 43, 50].
How can i reverse this? Is there a builtin function?
Anything that does what "desiredfunction" does, would be a great help.
?- desiredfunction([97, 42, 49, 43, 50], R).
R = 'a*1+2'.
Thank you.
string_to_list/2 is deprecated in favor of string_codes/2.
The predicate is bidirectional, meaning that you can plug in a list, and get a string back on the other side.
string_codes(R, [97, 42, 49, 43, 50])
Better yet, use atom_codes/2, which is also bidirectional, and is more widely supported among Prolog implementations:
atom_codes(R, [97, 42, 49, 43, 50])
This produces
a*1+2

ZIO 2013: Dolls

Your shop sells several different types of dolls. Each doll has a suggested price, and no
two types of doll have the same price. You would like to fix an actual selling price for
each doll so that dolls of different types are as different in price as possible. Due to
some government regulations, you can only modify the suggested price within a fixed
band of ±K—in other words, if the suggested price is p, you can pick any selling price
in the range {p− K, p− K + 1, . . . , p+ K −1, p+ K}. Of course, the selling price must
always be non-negative.
For instance, suppose there are four types of dolls with suggested prices 130, 210, 70
and 90 and you are allowed to modify prices within a band of 20. Then, you can adjust
the prices to 150, 210, 50 and 100, respectively, so that the minimum difference in price
between any two types of dolls is 50. (For the second doll, you could have picked any
price between 200 and 230.) You can check that this is the largest separation that you
can achieve given the constraint.
In each of the cases below, you are given a sequence of prices and the value of K. You
have to determine the maximum separation that you can achieve between all pairs in
the sequence if you are allowed to modify each price by upto ±K.
(a) K = 13. Sequence: 144, 152, 214, 72, 256, 3, 39, 117, 238, 280.
(b) K = 10. Sequence: 10, 48, 57, 32, 61, 74, 33, 45, 99, 81, 19, 24, 101.
(c) K = 20. Sequence: 10, 19, 154, 67, 83, 39, 54, 110, 124, 99, 139, 170
So basically, I just need to find the value of maximum separation without coding. I tried to devise an algorithm, but failed miserably, so I just started brute forcing it, by basically increasing/decreasing each of the prices by a certain value, but the bruteforcing applied here is just too tough due to the value of K. (It would have been simple for any K<6).
Can someone define a function or recurrence relation to calculate it? The solutions are up online, but they only give the answer as an integer and don't explain how to reach the solution. I am a beginner in programming, so try explaining using pseudocode/ little bit of C++, please. Thank you.
Source: http://www.iarcs.org.in/inoi/2013/zio2013/zio2013-qpaper.pdf
Solution: http://www.iarcs.org.in/inoi/2013/zio2013/zio2013-solutions.pdf
Here is a O(nlogn) algorithm.
To illustrate I will use the second example: 10, 48, 57, 32, 61, 74, 33, 45, 99, 81, 19, 24, 101 with K=10
Sort the list (10, 19, 24, 32, 33, 45, 48, 57, 61, 74, 81, 99, 101)
Use bisection to find the minimum separation x
For a trial value of x, assign the final values greedily placing them as small as possible while satisfying the conditions (non-negative, within K of original value, at least x greater than previous).
So let us start with x=10.
We will move as follows:
10->0 (can't go negative so this is smallest allowed)
19->10 (can't go within K=10 of the previous value)
24->20
32->30
33->40
45->50
48 becomes impossible. We can only assign values between 38 and 58, but none of these are more than 10 away from the previous 50.
We conclude that x=10 is too high a separation and we need to move lower.
You might try x=7 and find it is possible, x=9 find it is impossible, then try x=8:
10->0
19->9 (can only move to values 9->29)
24->17
32->25
33->33
45->41
48->49
57->56
61->64
74->72
81->80
99->89
101->97
And so we have found that x=8 is possible, x=9 is impossible and therefore x=8 is the maximum possible separation.

Mathematical representation of large numbers?

I am attempting to write a function which takes a large number as input (upwards of 800 digits long) and returns a simple formula of no complex math as a string.
By simple math, I mean just numbers with +,-,*,/,^ and () as needed.
'4^25+2^32' = giveMeMath(1125904201809920); // example
Any language would do. I can refactor it, just looking for some help with the logic.
Bonus. The shorter the output the better. Processing time is important. Also, mathematical accuracy is a must.
Update:
to clarify, all input values will be positive integers (no decimals)
I think the entire problem can be recast to a run-length encoding problem on the binary representation of the long integer.
For example, take the following number:
17976931348623159077293051907890247336179769789423065727343008115773
26758055009631327084773224075360211201138798713933576587897688144166
22492847430639474110969959963482268385702277221395399966640087262359
69162804527670696057843280792693630866652907025992282065272811175389
6392184596904358265409895975218053120L
This looks fairly horrendous. In binary, though:
>>> bin(_)
'0b11111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111100000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000
0000000'
Which is about 500 ones, followed by 500 zeroes. This suggests an expression like:
2**1024 - 2**512
Which is how I obtained the large number in the first place.
If there are no significantly long runs in the binary representation of the integer, this won't work well at all. 101010101010101010.... is the worst case.
Here is my attempt in Python:
def give_me_math(n):
if n % 2 == 1:
n = n - 1 # we need to make every odd number even, and add back one later
odd = 1
else:
odd = 0
exps = []
while n > 0:
c = 0
num = 0
while num <= n/2:
c += 1
num = 2**c
exps.append(c)
n = n - num
return (exps, odd)
Results:
>>> give_me_math(100)
([6, 5, 2], 0) #2**6 + 2**5 + 2**2 + 0 = 100
>>> give_me_math(99)
([6, 5, 1], 1) #2**6 + 2**5 + 2**1 + 1 = 99
>>> give_me_math(103)
([6, 5, 2, 1], 1) #2**6 + 2**5 + 2**2 + 2**1 + 1 = 103
I believe the results are accurate, but I am not sure about your other criteria.
Edit:
Result: Calculates in about a second.
>>> give_me_math(10**100 + 3435)
([332, 329, 326, 323, 320, 319, 317, 315, 314, 312, 309, 306, 304, 303, 300, 298, 295, 294, 289, 288, 286, 285, 284, 283, 282, 279, 278, 277, 275, 273, 272, 267, 265, 264, 261, 258, 257, 256, 255, 250, 247, 246, 242, 239, 238, 235, 234, 233, 227, 225, 224, 223, 222, 221, 220, 217, 216, 215, 211, 209, 207, 206, 203, 202, 201, 198, 191, 187, 186, 185, 181, 176, 172, 171, 169, 166, 165, 164, 163, 162, 159, 157, 155, 153, 151, 149, 148, 145, 142, 137, 136, 131, 127, 125, 123, 117, 115, 114, 113, 111, 107, 106, 105, 104, 100, 11, 10, 8, 6, 5, 3, 1], 1)
800 digit works fast too:
>>> give_me_math(10**800 + 3452)
But the output is too long to post here, which is OPs concern of course.
Time complexity here is 0(ln(n)), so it is pretty efficient.
In java, you should take a look at the BigDecimal class in java.math package.
I'd suggest you to have a look at
The GMP library (The GNU Multiple Precision Arithmetic Library) for performing the arithmetics
Take a look at integer factorization. The link redirects to Wikipedia which should give probably a good overview. However to be a bit more scientific:
Integer factorization (PDF) by Daniel Bernstein of the University of Illinois
Integer Factorization Algorithms (PDF) by Connelly Barnes of the Department of Physics, Oregon State University

How can I sort numbers as though they were words?

Ruby's Array#sort will, by default, sort numbers like this, in order of their value:
[11, 12, 13, 112, 113, 124, 125, 127]
I'd like to sort an array of numbers like this, as though they were words being alphabetized:
[11, 112, 113, 12, 124, 125, 127, 13]
How can I do this? (Ultimately, I want to do this with Hash keys, so if you want to answer that way instead, that's fine.) Also, is there a name for this type of sort?
You are all crqzy ))) I have a such solution:
a.sort_by &:to_s
Well, one way is to convert all of the values to strings, then convert them back.
a = [11, 12, 13, 112, 113, 124, 125, 127]
a = a.map(&:to_s).sort.map(&:to_i)
p a # => [11, 112, 113, 12, 124, 125, 127, 13]
You can pass in a block to sort that accepts two arguments and returns the result of your own custom-defined comparison function. The example should speak for itself, but should you have any questions, feel free to ask.
a = [11, 112, 113, 12, 124, 125, 127, 13]
new_a = a.sort do |x,y|
"%{x}" <=> "%{y}"
end
puts new_a
A note: I suspect that the reason you're looking for this sort of solution is because the objects you want sorted are not Integers at heart. It might be worthwhile and semantically more pleasing to subclass Integer. Although it will obviously make instantiation harder, it feels more correct, at least to me.

Resources