Related
I'm confused with the USACO Cowpatibility solution explanation and code.
The problem is defined here: http://usaco.org/index.php?page=viewproblem2&cpid=862.
Their solution is defined here: http://usaco.org/current/data/sol_cowpatibility_gold_dec18.html.
I know their linear solution requires the property of inclusion and exclusion (PIE), and I understand this property, but I am confused about how they implemented it. I'm looking for an explanation of these lines:
"This motivates the following inclusion-exclusion solution: for every subset of flavors, count how many pairs of cows that like all flavors within each subset. We add all the counts for subsets of size 1, then to avoid double-counting, we subtract all the counts for subsets of size 2. We then add all the counts of subsets of size 3, subtract all the counts of subsets of size 4, and add the counts of subsets of size 5."
How do they determine every possible subset, and what are these subsets? Why are there only 31N subsets? It would also be helpful if someone gives examples of what the subsets would be for their sample case.
They generated and stored subsets in order to keep track of the number of pairs of cows with 1 flavor in common, 2 flavors in common, 3 flavors in common, 4 flavors in common, and all 5 flavors in common. To do this, they used a map.
Now, there are 31N subsets because for each cow, you can create 31 combinations of favorite flavors. For example, Cow 1's favorite flavors of ice cream were 1, 2, 3, 4, 5. So the different subsets were:
{1, 0, 0, 0, 0} {1, 3, 0, 0, 0} {2, 5, 0, 0, 0} {1, 2, 5, 0, 0}
{1, 2, 0, 0, 0} {1, 4, 0, 0, 0} {1, 3, 4, 0, 0} {2, 3, 5, 0, 0}
{1, 2, 3, 0, 0} {1, 5, 0, 0, 0} {1, 3, 5, 0, 0} {3, 4, 5, 0, 0}
{1, 2, 3, 4, 0} {2, 3, 0, 0, 0} {2, 3, 4, 0, 0} {1, 2, 3, 5, 0}
{1, 2, 3, 4, 5} {2, 4, 0, 0, 0} {2, 4, 5, 0, 0} {1, 3, 4, 5, 0}
{2, 3, 4, 5, 0} {2, 0, 0, 0, 0} {3, 0, 0, 0, 0} {4, 0, 0, 0, 0}
{5, 0, 0, 0, 0} {3, 4, 0, 0, 0} {3, 5, 0, 0, 0} {4, 5, 0, 0, 0}
{1, 4, 5, 0, 0} {1, 2, 4, 0, 0} {1, 2, 4, 5, 0}
As you can see, there are 31 subsets. (This is because there are 2^5 = 32 sets that can be made, including an empty set. 32 - 1 = 31.) Since N ≤ 50,000, you can generate 31N subsets. After scanning through the input, the code generated the subsets for each cow and added them to a map:
map<S5, int> subsets;
They mapped each combination to the number of times it was seen. Some examples of entries for the sample input would be:
{
[{1, 0, 0, 0, 0}, 2], # 2 cows, Cow 1 and Cow 2 both like flavor 1
[{8, 10, 0, 0, 0}, 2], # 2 cows, Cow 2 and Cow 3 both like flavors 8 and 10
[{50, 60, 80, 0, 0}, 1], # 1 cow, Cow 4 liked flavors 50, 60, 80
# and so on...
}
Finally, based the number of nonzero numbers in the subset, the algorithm applies the inclusion-exclusion principle. It simply iterates through all 31N subsets, and either adds or subtracts the count stored in the map for that subset. (If it was 1, 3, or 5 nonzero numbers the counts were added; else they were subtracted.) It then subtracts this answer from N * (N-1) / 2 to output the number of pairs of cows that aren't compatible.
I hope this explanation helps! Good luck for future contests!
There are 31N distinct subsets because each cow has five possible flavor choices. Specifically, this line explains the subsets:
we can explicitly generate all the subsets of flavors where at least
one cow likes all the flavors in that subset
The way to do that is to iterate over all N cows then construct the power set of flavors that they like, excluding the empty set. There are 2^5 sets in the power set, so removing the empty set results in 31. Therefore, there are 31N sets total.
An example is quite helpful here, taking the sample input:
4
1 2 3 4 5 # Cow 0
1 2 3 10 8 # Cow 1
10 9 8 7 6 # Cow 2
50 60 70 80 90 # Cow 3
The subsets will be:
{
{1}, {1, 2}, {1, 3}, ..., {2, 3, 4, 5}, {1, 2, 3, 4, 5}, # Cow 0
{1}, {1, 2}, {1, 3}, ..., {2, 3, 10, 8}, {1, 2, 3, 10, 8}, # Cow 1
...
}
Each cow generates 31 subsets. From there, the algorithm counts the number of cows that generate a specific subset (for example, note that {1} is generated by both cow 0 and 1, we just keep track of how many cows generate each subset), and applies inclusion-exclusion based on the subset size.
Nice problem, I used to do USACO and they had really interesting problems which still stand out amongst the "clever" interview questions a lot of companies give. :)
I'm fairly new to Mathematica and I've come across a probably stupid problem.
I have a matrix {{1,1,1,2,2,2,2,2},{-1,0,1,-2,-1,0,1,2}} and I would like to sort the second row but also that the positions of the elements of the first row are sorted at the same time.
Thus, the array would become {{2,1,2,1,2,1,2,2},{-2,-1,-1,0,0,1,1,2}}. I hope is it clear. Do you know how I could proceed?
Thanks in advance.
Let
list = {{1, 1, 1, 2, 2, 2, 2, 2}, {-1, 0, 1, -2, -1, 0, 1, 2}}
then
{list[[1]][[Ordering[list[[2]]]]], Sort[list[[2]]]}
gives the output you are looking for.
For future reference, you might want to think about posting Mathematica questions at https://mathematica.stackexchange.com.
Another approach:
SortBy[Transpose[data],Last]//Transpose
{{2, 1, 2, 1, 2, 1, 2, 2}, {-2, -1, -1, 0, 0, 1, 1, 2}}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Given an array of 0 and 1, e.g. array[] = {0, 1, 0, 0, 0, 1, ...}, how I can predict what the next value will be with the best possible accuracy?
What kind of methods are best suited for this kind of task?
The prediction method would depend on the interpretation of data.
However, it looks like in this particular case we can make some general assumptions that might justify use of certain machine learning techniques.
Values are generated one after another in chronological order
Values depend on some (possibly non-observable) external state. If the state repeats itself, so do the values.
This is a pretty common scenario in many machine learning contexts. One example is the prediction of stock prices based on history.
Now, to build the predictive model you'll need to define the training data set. Assume our model looks at the last k values. In case if k=1, we might end up with something similar to a Markov chain model.
Our training data set will consist of k-dimensional data points together with their respective dependent values. For example, suppose k=3 and we have the following input data
0,0,1,1,0,1,0,1,1,1,1,0,1,0,0,1...
We'll have the following training data:
(0,0,1) -> 1
(0,1,1) -> 0
(1,1,0) -> 1
(1,0,1) -> 0
(0,1,0) -> 1
(1,0,1) -> 1
(0,1,1) -> 1
(1,1,1) -> 1
(1,1,1) -> 0
(1,1,0) -> 1
(1,0,1) -> 0
(0,1,0) -> 0
(1,0,0) -> 1
Now, let's say you want to predict the next value in the sequence. The last 3 values are 0,0,1, so the model must predict the value of the function at (0,0,1), based on the training data.
A popular and relatively simple approach would be to use a multivariate linear regression on a k-dimensional data space. Alternatively, consider using a neural network if linear regression underfits the training data set.
You might need to try out different values of k and test against your validation set.
You could use a maximum likelihood estimator for the Bernoulli distribution. In essence you would:
look at all observed values and estimate parameter p
then use p to determine the next value
In Python this could look like this:
#!/usr/bin/env python
from __future__ import division
signal = [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0]
def maximum_likelihood(s, last=None):
"""
The maximum likelihood estimator selects the parameter value which gives
the observed data the largest possible probability.
http://mathworld.wolfram.com/MaximumLikelihood.html
If `last` is given, only use the last `n` values.
"""
if not last:
return sum(s) / len(s)
return sum(s[:-last]) / last
if __name__ == '__main__':
hits = []
print('p\tpredicted\tcorrect\tsignal')
print('-\t---------\t-------\t------')
for i in range(1, len(signal) - 1):
p = maximum_likelihood(signal[:i]) # p = maximum_likelihood(signal[:i], last=2)
prediction = int(p >= 0.5)
hits.append(prediction == signal[i])
print('%0.3f\t%s\t\t%s\t%s' % (
p, prediction, prediction == signal[i], signal[:i]))
print('accuracy: %0.3f' % (sum(hits) / len(hits)))
The output would like this:
# p predicted correct signal
# - --------- ------- ------
# 1.000 1 False [1]
# 0.500 1 True [1, 0]
# 0.667 1 True [1, 0, 1]
# 0.750 1 False [1, 0, 1, 1]
# 0.600 1 False [1, 0, 1, 1, 0]
# 0.500 1 True [1, 0, 1, 1, 0, 0]
# 0.571 1 False [1, 0, 1, 1, 0, 0, 1]
# 0.500 1 True [1, 0, 1, 1, 0, 0, 1, 0]
# 0.556 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1]
# 0.600 1 False [1, 0, 1, 1, 0, 0, 1, 0, 1, 1]
# 0.545 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0]
# 0.583 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1]
# 0.615 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]
# 0.643 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1]
# 0.667 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1]
# 0.688 1 False [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1]
# 0.647 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0]
# 0.667 1 False [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1]
# 0.632 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0]
# 0.650 1 True [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1]
# accuracy: 0.650
You could vary the window size for performance reasons or to favor recent events.
In above example, if we would estimate the the next value by looking only at the last 3 observed values, we could increase our accuracy to 0.7.
Update: Inspired by Narek's answer I added a logistic regression classifier example to the gist.
You can predict by calculating the probabilities of 0s and 1s and make their probability ranges and then draw a random number between 0 and 1 to predict.....
If these are series of numbers that are generated each time after some reset event, and next numbers are somehow related to previous ones, you could create a tree (binary tree with two branches at each node in your case) and feed in such historical series from the root, adjusting weights (say a count) on each branch you follow.
Could divide such counts by the number of series you entered before using them, or keep a number on each node too, increased before choosing a branch. That way root node contains number of series entered.
Then, as you feed it a new sequence you can see which branch is "hotter" (would make nice visualization as heatmap/tree btw) to follow, especially if sequence is long enough. That is, assuming order of items in sequence plays a role in what comes next.
I have the following problem.
I need to build a very large number of definitions(*) such as
f[{1,0,0,0}] = 1
f[{0,1,0,0}] = 2
f[{0,0,1,0}] = 3
f[{0,0,0,1}] = 2
...
f[{2,3,1,2}] = 4
...
f[{n1,n2,n3,n4}] = some integer
...
This is just an example. The length of the argument list does not need to be 4 but can be anything.
I realized that the lookup for each value slows down with exponential complexity when the length of the argument list increases. Perhaps this is not so strange, since it is clear that in principle there is a combinatorial explosion in how many definitions Mathematica needs to store.
Though, I have expected Mathematica to be smart and that value extract should be constant time complexity. Apparently it is not.
Is there any way to speed up lookup time? This probably has to do with how Mathematica internally handles symbol definition lookups. Does it phrases the list until it finds the match? It seems that it does so.
All suggestions highly appreciated.
With best regards
Zoran
(*) I am working on a stochastic simulation software that generates all configurations of a system and needs to store how many times each configuration occurred. In that sense a list {n1, n2, ..., nT} describes a particular configuration of the system saying that there are n1 particles of type 1, n2 particles of type 2, ..., nT particles of type T. There can be exponentially many such configurations.
Could you give some detail on how you worked out that lookup time is exponential?
If it is indeed exponential, perhaps you could speed things up by using Hash on your keys (configurations), then storing key-value pairs in a list like {{key1,value1},{key2,value2}}, kept sorted by key and then using binary search (which should be log time). This should be very quick to code up but not optimum in terms of speed.
If that's not fast enough, one could think about setting up a proper hashtable implementation (which I thought was what the f[{0,1,0,1}]=3 approach did, without having checked).
But some toy example of the slowdown would be useful to proceed further...
EDIT: I just tried
test[length_] := Block[{f},
Do[
f[RandomInteger[{0, 10}, 100]] = RandomInteger[0, 10];,
{i, 1, length}
];
f[{0, 0, 0, 0, 1, 7, 0, 3, 7, 8, 0, 4, 5, 8, 0, 8, 6, 7, 7, 0, 1, 6,
3, 9, 6, 9, 2, 7, 2, 8, 1, 1, 8, 4, 0, 5, 2, 9, 9, 10, 6, 3, 6,
8, 10, 0, 7, 1, 2, 8, 4, 4, 9, 5, 1, 10, 4, 1, 1, 3, 0, 3, 6, 5,
4, 0, 9, 5, 4, 6, 9, 6, 10, 6, 2, 4, 9, 2, 9, 8, 10, 0, 8, 4, 9,
5, 5, 9, 7, 2, 7, 4, 0, 2, 0, 10, 2, 4, 10, 1}] // timeIt
]
with timeIt defined to accurately time even short runs as follows:
timeIt::usage = "timeIt[expr] gives the time taken to execute expr,
repeating as many times as necessary to achieve a total time of \
1s";
SetAttributes[timeIt, HoldAll]
timeIt[expr_] := Module[{t = Timing[expr;][[1]], tries = 1},
While[t < 1.,
tries *= 2;
t = Timing[Do[expr, {tries}];][[1]];
];
Return[t/tries]]
and then
out = {#, test[#]} & /# {10, 100, 1000, 10000, 100000, 100000};
ListLogLogPlot#out
(also for larger runs). So it seems constant time here.
Suppose you enter your information not like
f[{1,0,0,0}] = 1
f[{0,1,0,0}] = 2
but into a n1 x n2 x n3 x n4 matrix m like
m[[2,1,1,1]] = 1
m[[1,2,1,1]] = 2
etc.
(you could even enter values not as f[{1,0,0,0}]=1, but as f[{1,0,0,0},1] with
f[li_List, i_Integer] := Part[m, Apply[Sequence, li + 1]] = i;
f[li_List] := Part[m, Apply[Sequence, li + 1]];
where you have to initialize m e.g. by m = ConstantArray[0, {4, 4, 4, 4}];)
Let's compare timings:
testf[z_] :=
(
Do[ f[{n1, n2, n3, n4}] = RandomInteger[{1,100}], {n1,z}, {n2,z}, {n3,z},{n4,z}];
First[ Timing[ Do[ f[{n2, n4, n1, n3}], {n1, z}, {n2, z}, {n3, z}, {n4, z} ] ] ]
);
Framed[
ListLinePlot[
Table[{z, testf[z]}, {z, 22, 36, 2}],
PlotLabel -> Row[{"DownValue approach: ",
Round[MemoryInUse[]/1024.^2],
" MB needed"
}],
AxesLabel -> {"n1,n2,n3,n4", "time/s"},ImageSize -> 500
]
]
Clear[f];
testf2[z_] :=
(
m = RandomInteger[{1, 100}, {z, z, z, z}];
f2[ni__Integer] := m[[Sequence ## ({ni} + 1)]];
First[ Timing[ Do[ f2[{n2, n4, n1, n3}], {n1, z}, {n2, z}, {n3, z}, {n4, z}] ] ]
)
Framed[
ListLinePlot[
Table[{z, testf2[z]}, {z, 22, 36, 2}],
PlotLabel -> Row[{"Matrix approach: ",
Round[MemoryInUse[]/1024.^2],
" MB needed"
}],
AxesLabel -> {"n1,n2,n3,n4", "time/s"}, ImageSize -> 500
]
]
gives
So for larger sets up information a matrix approach seems clearly preferrable.
Of course, if you have truly large data, say more GB than you have RAM, then you just
have to use a database and DatabaseLink.
I have a problem similar to IntegerPartitions function, in that I want to list all non-negative integer xi's such that, for a given list of integers {c1,c2,...,cn} and an integer n:
x1*c1+x2*c2+...+xn*cn=n
Please share your thoughts. Many thanks.
The built-in function FrobeniusSolve solves the case where the c1, c2, ..., cn are positive integers (and the right hand side is not n):
In[1]:= FrobeniusSolve[{2, 3, 5, 6}, 13]
Out[1]= {{0, 1, 2, 0}, {1, 0, 1, 1}, {1, 2, 1, 0}, {2, 1, 0, 1}, {2,
3, 0, 0}, {4, 0, 1, 0}, {5, 1, 0, 0}}
Is this the case you need, or do you need negative c1, c2, ..., cn also?
Construct your list of ci's and coefficients using
n = 10;
cList = RandomInteger[{1, 20}, n]
xList = Table[Symbol["x" <> ToString[i]], {i, n}]
Then, if there's a set of solutions for non-negative xi's, it will be found by
Reduce[cList.xList == n && And##Thread[xList >= 0], xList, Integers]