Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Comments on What's the complexity of this algorithm for solving the maximum clique NP-Complete problem?

Parent

What's the complexity of this algorithm for solving the maximum clique NP-Complete problem?

+3
−0

I believe I have discovered a quasi-polynomial algorithm for solving an NP-Complete problem: the maximum clique problem.

Of course, I doubt the correctness of my discovery, because as we know, that's known to be quite difficult and unlikely.

I'll present here the essential algorithm (without optimizations that are unnecessary for reaching QP complexity). I'm interested in finding whether my evaluation of the worst-case complexity is correct.

The algorithm below is recursive:

  1. Take as input the minimum size that a solution must have to be a better clique than those known so far (initially, use 1). Let's call it Z.

  2. Take as input a problem that has nodes, some of which are connected through edges. Let's call this problem P.

  3. Create an empty solution list. Let's call it S.

  • 2bis) [Edit: I forgot to include this step]

    Remove any nodes that have less than Z-1 edges. Repeat this operation as necessary.

  1. Create a copy of P. Let's call it A. It holds the only candidates that can be selected in step 4. At the moment, all nodes of P are also contained in A.

loop:

  1. Find the best candidate node. Let's call it X.

    The candidate node must exist in A. From those that exist in A, select the one with less edges in P, even if this might seem counter-intuitive.

  2. If there are no candidates, print S (it might be empty), and terminate (if we were recursing, continue at step 9 of the previous level of recursion; otherwise, we've finished).

  3. Create a temporary solution list containing exactly X. Let's call it ST.

  4. Create a smaller problem Q, which is a copy of P, but removing any nodes not connected with X, and also removing X.

  5. Solve (recursively, goto step 0) the problem Q. Pass MAX(Z-1, 1) as the input for step 0, and Q as the input for step 1.

    Because X is the least-connected node, Q is the smallest problem we could try to solve. Considering that p (which is 0<=p<=1) is the frequency of edges in the problem P, and n is the number of nodes in the problem P, Q will have no more than n*p nodes.

  6. Append the output of the previous step to the list ST.

  7. If the size of the list ST is greater or equal than Z, replace S with the contents of ST, and update Z to be the size of ST plus 1.

  8. Remove ST.

  9. Create a copy of P. Let's call it AT.

  10. Remove from AT all nodes that are connected to X, and remove also X from A.

    The reason is that we've found the best solution that contains X, and thus if we want a better solution, it cannot contain X, and it must contain at least one node not compatible with X. Actually, because we want a better solution, we need at least two nodes not connected to X. Thus,

  11. For each node that exists in A and/or in AT, if in any of those graphs the node is not connected to any other nodes, remove such node from all of P, A, and AT. (Edited, as I had forgotten a detail.)

    These can only start a solution as good as S, but not better.

  12. Remove X from P.

  • 15bis) [Edit: I forgot to include this step]

    Remove any nodes that have less than Z-1 edges in P from both P, A, and AT.

  1. If AT contains less nodes than A, replace A with the contents of AT.

    This is an optimization, so that we use the smallest A (alternatives list), which reduces the number of iterations in the loop. This reduces the base of the exponential function, but is not necessary for the algorithm being QP.

  2. Remove AT.

  3. goto step 4 (loop);

Signed-off-by: Alejandro Colomar Andrés <[email protected]>

(Note: This was all human generated; I haven't used any LLM or AI at all for developing this algorithm; just my brain.)

This is the first time I publish this algorithm. I will soon publish my own implementation, which contains a few important optimizations. (If you try implementing the above, you'll find it's very very slow, and some optimizations not mentioned here are necessary to make it be actually fast.)


In steps 4 and 8 are the key to the super-polynomial complexity.

The number of times we repeat step 4 across all recursion levels is essential to the complexity of the algorithm. (Then, that's multiplied by the complexity of each iteration, but that is polynomial, so let's ignore that part.)

Some interesting facts:

  • The depth of recursion will not grow past the size of the maximum clique.
  • The size of the problems P will diminish until it's 0 at the depth of recursion of the size of the maximum clique.
  • When getting close to that recursion level, p will grow to 1.

The amount of iterations of step 4 in a given recursion level is bound by the number of nodes at that level.

The first levels of recursion will reduce the size faster than n*p^d where d is the depth level, given we choose candidates with number of edges below average. We might worry about the deeply recursive levels, where we got rid of the nodes with few edges, and only highly connected nodes remain.

Let's start by assuming that p is homogeneous across all nodes, so that all nodes have n*p edges, all the time. It's obvious that the size of the problem at each level of recursion will be p times the size of the previous level of recursion. That way, we'll reach size 1 (and thus terminate recursing) when n*p^d == 1, where d is the depth of recursion. We can calculate d = log(n)/log(1/p).

Now, if we drop the assumption that p is homogeneous, we have to calculate the size as n*p1*p2*p3*p4..., where p1,p2,p3... are the pi values of the best candidate X at each level of recursion. Because on average they must be more or less equal to p, some will be smaller, and others will be higher. We also start by the lowest values, and only reach the high values as needed, so on average we remain below p. Now, similar to how the geometric mean is never larger than the arithmetic mean, it seems obvious that the multiplication of non-homogeneous values will always result in a value smaller than the multiplication of homogeneous values.

By the end of the run of this algorithm, we'll be trying the remaining (highly connected) nodes at low recursion depths, which might also seem problematic. However, at that point, the number of edges of each node has dropped below half of the original, and thus, p must again be below average for those nodes.

As an exception to the above paragraph, in problems with disjoint subgraphs, with low p, the initial removal of nodes might not affect the p of the remaining last nodes. However, each of those disjoint subgraphs can be considered a smaller problem with a higher p, and the same applies to each smaller problem. Near the end, we'll face a problem of small n and high p, and the rules above will apply.

Thus, I believe I've proved that regardless of the distribution of p, the complexity of the exponent is bound by log(n)/log(1/p).

If the exponent is bound by a logarithm, and of course, the number of iterations of the loop in a given recursive call is bound by n, we can find the upper bound for the number of total iterations of step 4 by n^(log(n)/log(1/p)).

I've actually implemented this algorithm in a combination of shell scripts and C programs, and the number of iterations of each level of recursion, and the maximum depth reached, both seem to agree with these theoretical bounds. Actually, while they never surpass those bounds, they seem to be even better than those theoretical bounds. Also, I've run the implementation with several of the benchmarks I found at https://iridia.ulb.ac.be/~fmascia/maximum_clique/DIMACS-benchmark#detC125.9, and it agrees with the size of the maximum cliques, which makes me confident of the correctness of the algorithm (unrelated to its complexity).

Is all of this correct, or did I make any mistakes in my evaluation of the complexity?

Here are a few runs that seem to agree with the theory here:

N = 100, p = 0.9
$ time npc-rand 100 0.9 0 | npc-solve 100 | wc -l
Size: 100
Frequency: 0.900000
Seed: 0
     13 0
    151 1
   1369 2
   8148 3
  18268 4
   8259 5
    464 6
     11 7
      9 8
      9 9
      9 10
      9 11
      9 12
      9 13
      9 14
      9 15
      9 16
      9 17
      9 18
      9 19
      9 20
      8 21
      7 22
      6 23
      5 24
      4 25
      3 26
      2 27
      2 28
      1 29
30

real	8m42.176s
user	6m55.197s
sys	1m52.039s
N = 60, p = 0.9
$ time npc-rand 60 0.9 0 | npc-solve 60 | wc -l
Size: 60
Frequency: 0.900000
Seed: 0
      9 0
     39 1
     48 2
     11 3
      2 4
      2 5
      2 6
      2 7
      2 8
      2 9
      2 10
      2 11
      2 12
      2 13
      2 14
      2 15
      2 16
      2 17
      2 18
      2 19
      2 20
      2 21
      1 22
      1 23
24

real	0m1.142s
user	0m1.483s
sys	0m0.288s
History

4 comment threads

Two questions (21 comments)
Implementation source code (4 comments)
General comment (8 comments)
Translation to SAT (2 comments)
Post
+3
−0

(Status of this answer: mostly complete, but I lack sufficient knowledge in the area)

The algorithm as described in the OP and with the clarifications in the comments appears equivalent to the branch-and-bound algorithm described in Li & Quan 2010, p. 129. Even the heuristic of choosing the minimum-degree vertex is the same!

ArXiv preprint 1505.04969 appears to show that this branch-and-bound algorithm exhibits exponential complexity for random graphs. It also links to another paper, "Analysis of an exhaustive search algorithm in random graphs and the $n^{c log n}$-asymptotics", which seems pertinent.

"Theorem 1" of the first paper says:

The average running time of exhaustive search for max independent set when running in (n, p)-binomial random graph G of order n is:

  1. subexponential when p is constant, or p = φ(n)/n for some function φ such that φ(n) = o(n), with φ → ∞ when n → ∞;
  2. exponential for p = k/n, if k is a fixed constant.

I have not yet deciphered their proof of this assertion.

History

2 comment threads

Finding the worst case (28 comments)
A few comments (1 comment)
Finding the worst case
alx‭ wrote 4 months ago · edited 4 months ago

A worst-case counter-example that would prove exponential behavior would have to be worse than

B^(log(n)/log(1/p))

Where B is some base, which we really don't care about.

The exponent can only come from the depth of the recursion, and depth can only count while the working graphs are not complete (once the graph is complete, there's exactly one iteration per depth level, which makes that part linear). This includes almost-complete (Turán; maybe also other types?) graphs, since they are also iterated just once due to optimizations (and actually, can be turned into complete graphs with stronger optimizations that I mentioned in comments).

Is it possible to design a graph that would reach depth log(n)/log(1/p)+1 with this algorithm before reaching a complete graph or a Turán graph?

Is this question itself too difficult (NP-Complete)? Or is it reasonable to expect that some expert would be able to design such a counter-example if it exists?

Skipping 1 deleted comment.

alx‭ wrote 4 months ago · edited 4 months ago

I'm now trying to design such a worst case. For a worst case to exist, it must certainly have a clique of at least size log(N)/log(1/p)+1. Otherwise, we can't possibly reach such a depth level at all.

Now I'll try to investigate other properties of such a graph.

I'll maybe also try a brute-force search of such a problem for small sizes, by generating all possible graphs of a given size, and finding whether any of them has these properties. I'm not sure if this will be possible, but by discarding graphs that don't have enough edges for a solution of size log(n)/log(1/p) might make it feasible.

alx‭ wrote 4 months ago · edited 4 months ago

Ohhh, now that I'm trying small problems (for brute-forcing) I realize about something very weird.

From the equation n * p^d = 1, when we isolate d, we get d = log(n)/log(1/p). But if we fill a small value for n, say 10, and a hard value for p, say 0.9, we get: d = log(10)/log(1/0.9). But then d ~= 22, which is clearly impossible (we can't iterate until a depth of 22 with a graph of size 10.

For larger n, this equation has a plausible value (for n = 100, d ~= 44). The intercept for p=0.9 is at n~=33 (from n*p^n=1).

I'm not yet sure about the implications of this. But it's weird. :)

Skipping 1 deleted comment.

alx‭ wrote 4 months ago · edited 4 months ago

Actually, that inconsistency was because of a mistake. I didn't take into account that the graph size decreases by n*(1-p)+1 instead of n*(1-p) in each recursion level. That means the equation should have been n*p^d=d instead of n*p^d=1. Thus, the upper bound of d isn't log(n)/log(1/p). It's a bit more difficult to calculate:

n*p^d = d;
d*log(p) = log(d/n);
d*log(p) = log(d) - log(n);
d*log(1/p) = log(n) - log(d);

Passing the first line to WolframAlpha, it isolates d as -W(-n * log(p))/ log(p)), where W() is the product log function. I don't grasp what that function means, but as far as I can see, for large n, the first approximation is a logarithm (and then a log of a log, plus o(1)), so we could simplify it as log(n * log(1/p))/log(1/p), which keeps the exponent logarithmic.

alx‭ wrote 4 months ago

I've been able to find enough small worst cases to see some interesting patterns.

I applied a few rules to reduce the amount of cases I tested:

  • If the graph has any nodes with zero edges, discard it, since we can remove the node and solve a graph of size N-1.
  • If the graph has any nodes with only a missing edge, discard it, since we can easily transform the graph into one of size N-1.

That allowed me to solve graph of size 1..7 (or 6, I don't remember well). After that, I was able to see that from the worst cases, there was always at least one that was symmetric along the two diagonals. By induction, I assumed I could reduce the search of the worst case to those that are symmetric along both diagonals. That allowed me to search graphs of size <=10 (IIRC). Then, I was able to see that from the worst cases, there was always at least one that was symmetric along 4 axes. This allowed me to search graphs of size 13. ...

alx‭ wrote 4 months ago

And finally, I also found out I could center the maximum clique, by placing a large block of 1s in the middle of the matrix. The block was always at least as large as the block of the matrix of size N-2.

With all that, I've found the following worst cases:

$ find wc* | sort -V | xargs head -n999
==> wc1 <==
1

==> wc2 <==
11
11

==> wc3 <==
111
111
111

==> wc4 <==
1001
0110
0110
1001

==> wc5 <==
10001
01110
01110
01110
10001

==> wc6 <==
100001
011110
011110
011110
011110
100001

==> wc7 <==
1001001
0110110
0111110
1011101
0111110
0110110
1001001

==> wc8 <==
10000001
01111110
01111110
01111110
01111110
01111110
01111110
10000001

==> wc9 <==
100010001
011000110
011111110
001111100
101111101
001111100
011111110
011000110
100010001

==> wc10 <==
1000000001
0110000110
0111111110
0011111100
0011111100
0011111100
0011111100
0111111110
0110000110
1000000001
alx‭ wrote 4 months ago · edited 4 months ago

...

==> wc11 <==
11001110011
11110001111
01111111110
01111111110
10111111101
10111111101
10111111101
01111111110
01111111110
11110001111
11001110011

==> wc12 <==
100001100001
011100001110
011111111110
011111111110
001111111100
101111111101
101111111101
001111111100
011111111110
011111111110
011100001110
100001100001

==> wc13 <==
1100011100011
1111100011111
0111111111110
0111111111110
0111111111110
1011111111101
1011111111101
1011111111101
0111111111110
0111111111110
0111111111110
1111100011111
1100011100011

==> wc14 <==
11000111100011
11111000011111
01111111111110
01111111111110
01111111111110
10111111111101
10111111111101
10111111111101
10111111111101
01111111111110
01111111111110
01111111111110
11111000011111
11000111100011

==> wc15 <==
101000111000101
011100111001110
111111000111111
011111111111110
001111111111100
001111111111100
110111111111011
110111111111011
110111111111011
001111111111100
001111111111100
011111111111110
111111000111111
011100111001110
101000111000101
alx‭ wrote 4 months ago

...

==> wc16 <==
1100001111000011
1111110000111111
0111111111111110
0111111111111110
0111111111111110
0111111111111110
1011111111111101
1011111111111101
1011111111111101
1011111111111101
0111111111111110
0111111111111110
0111111111111110
0111111111111110
1111110000111111
1100001111000011

==> wc17 <==
10100011111000101
01111001110011110
11111110001111111
01111111111111110
01111111111111110
00111111111111100
10111111111111101
11011111111111011
11011111111111011
11011111111111011
10111111111111101
00111111111111100
01111111111111110
01111111111111110
11111110001111111
01111001110011110
10100011111000101

==> wc18 <==
110001100001100011
111110011110011111
011111100001111110
011111111111111110
011111111111111110
101111111111111101
101111111111111101
010111111111111010
010111111111111010
010111111111111010
010111111111111010
101111111111111101
101111111111111101
011111111111111110
011111111111111110
011111100001111110
111110011110011111
110001100001100011
alx‭ wrote 4 months ago

...

==> wc19 <==
1110001111111000111
1111110011100111111
1111111100011111111
0111111111111111110
0111111111111111110
0111111111111111110
1011111111111111101
1011111111111111101
1101111111111111011
1101111111111111011
1101111111111111011
1011111111111111101
1011111111111111101
0111111111111111110
0111111111111111110
0111111111111111110
1111111100011111111
1111110011100111111
1110001111111000111
alx‭ wrote 4 months ago

And here's the debug output of the program, which shows the amount of times each recursion depth level is reached.

$ find c* | sort -V | xargs head -n999
==> c1 <==
      1 0

==> c2 <==
      1 0
      1 1

==> c3 <==
      1 0
      1 1
      1 2

==> c4 <==
      1 0
      1 1

==> c5 <==
      2 0
      2 1
      1 2

==> c6 <==
      2 0
      2 1
      1 2
      1 3

==> c7 <==
      2 0
      2 1
      2 2
      1 3

==> c8 <==
      2 0
      2 1
      1 2
      1 3
      1 4
      1 5

==> c9 <==
      3 0
      3 1
      3 2
      2 3
      1 4

==> c10 <==
      3 0
      3 1
      2 2
      2 3
      1 4
      1 5

==> c11 <==
      2 0
      4 1
      4 2
      4 3
      3 4
      2 5
      1 6

==> c12 <==
      3 0
      3 1
      3 2
      3 3
      2 4
      2 5
      1 6
      1 7

==> c13 <==
      2 0
      4 1
      4 2
      4 3
      3 4
      2 5
      2 6
      2 7
      1 8

...

alx‭ wrote 4 months ago

...

==> c14 <==
      2 0
      4 1
      4 2
      4 3
      3 4
      3 5
      2 6
      2 7
      1 8
      1 9

==> c15 <==
      3 0
      6 1
      6 2
      6 3
      5 4
      4 5
      3 6
      2 7
      1 8

==> c16 <==
      2 0
      4 1
      4 2
      4 3
      3 4
      3 5
      2 6
      2 7
      2 8
      2 9
      1 10
      1 11

==> c17 <==
      3 0
      6 1
      6 2
      6 3
      6 4
      6 5
      5 6
      4 7
      3 8
      2 9
      1 10

==> c18 <==
      3 0
      5 1
      5 2
      5 3
      4 4
      4 5
      3 6
      3 7
      2 8
      2 9
      1 10
      1 11

==> c19 <==
      2 0
      4 1
      8 2
      8 3
      8 4
      8 5
      7 6
      6 7
      5 8
      4 9
      3 10
      2 11
      1 12
alx‭ wrote 4 months ago · edited 4 months ago

At first glance, I observe a couple of trivial optimizations: if a graph has one node that has zero edges (ignoring edges connecting to fully connected nodes), it can't be part of the maximum clique, and can be removed from both P, A, and AT.

And if it has exactly one edge (ignoring ...), and there's at least one node with two or more edges (ignoring ...), then it can't be part of the maximum clique either, and can also be removed from the three graphs.

I'll apply that optimization, and search again for the worst case, and see how those change. I've already played a little bit with this optimization, and it reduces the worst cases significantly, while being slightly good in the average case.

Also, even if the induction by which I reduced the search of worst cases to very symmetric cases was slightly wrong, I don't expect worse cases to be much worse than these. After all, for a worst case to be worst, it should still be fractal (each graph at all stages should be worst cases).

alx‭ wrote 4 months ago · edited 4 months ago

Regarding the worst cases:

They seem to be fractal, which I was expecting. Picking any node to solve a subset of the problem, will give us a worst case (or similar to a worst case) of a smaller size. Also, nodes range smoothly from very unconnected at one end, to very connected at the other end.

Here's a chart of graph sizes, and the p for each of them:

$ cat p.tsv 
1	-
2	1.000
3	1.000
4	0.333
5	0.400
6	0.466
7	0.523
8	0.571
9	0.500
10	0.466
11	0.745
12	0.636
13	0.769
14	0.780
15	0.714
16	0.800
17	0.779
18	0.764
19	0.847

From here, it's not obvious whether p will converge to 1 or it will converge below 1.

alx‭ wrote 4 months ago · edited 4 months ago

Regarding p, I suspect p will not converge to 1, because the worst case seems to have p similar to that of the random hardest cases (and those ones don't seem to converge to 1). If it doesn't converge to 1, it will remain far from being exponential (unless my calculations are wrong).

Regarding the experimental complexity, we see that the exponent has a value of 2 in the worst case of size 11, and a value of 3 in the worst case of size 19. This doesn't seem to be linear, although we have very few points so this experiment can't be conclusive.

All the evidence seems to indicate that this won't be exponential, although because brute force is very limited, it's not conclusive.

clemens‭ wrote 4 months ago

@alx: Very interesting. The difficulty remains the small size of the samples. Random SAT instances seem to have exponentially increasing hardness—but at about a 1% increase per additional variable. This would correspond (via the SAT→MaxClique translation) to about a 0.08% increase per additional node in one's graph.

alx‭ wrote 4 months ago

But these are worst cases; not random. I've tried all possible graphs of size 1..6, and solved them all, and inspected the number of iterations needed to solve them, to determine which case was the hardest. Then, I tried all possible 2-way-symmetric graphs of size 7..10, and solved them all. Then, I tried all possible 4-way-symmetric graphs of size 11..13, and solved them all. And then tried all possible 4-way-symmetric graphs of size 14..19 that had a central block of 1s at least as large as the worst case of size N-2, and also solved them. So these are really the worst cases, and I expect their hardness should grow much faster than random samples.

Still, it could be that even the worst case doesn't grow that much...

I guess the only way this can be resolved is theoretically; by checking whether the reasoning makes sense or not. Did you analyze the assertion that by choosing a node wisely you could reduce the SAT instance exponentially?

alx‭ wrote 4 months ago · edited 4 months ago

One thing to note is that the worst cases seem to be fractals; and it makes sense, because after finding a pivot node, the subgraphs need to remain worst cases. And I don't think the amount of recursion in the fractal can grow linearly with the graph size. I'm not an expert in fractals, but it seems logarithms appear naturally in fractals, and thus it would make sense to expect that the exponent (which is the recursion depth of these fractals) be logarithmic, and thus the problem QP.

clemens‭ wrote 4 months ago

@alx: I'm not entirely sure right now. But of interest: it looks to me as though the most difficult random graphs for SAT have a $p$ of about $1-\frac{4.26}{2n}$. (And random SAT is still an exponentially hard problem for the best algorithms.) So heuristically speaking we expect connectivity to become gradually lower as one deepens one's search.

alx‭ wrote 4 months ago · edited 4 months ago

Hmmmm, if p would indeed converge to 1, the problem would be exponential.

Considering the complexity seemed to be n ^ (log(n) / log(1/p)), if p is growing, the complexity would be n ^ (log(n) / log(1/(1-C/n))), which for large n and small C can be approximated as n ^ (n * log(n) / C). So I should check whether p converges to 1 or not.

I'm running some more experiments at the moment.

clemens‭ wrote 4 months ago

@alx: The 2015 arXiv preprint https://arxiv.org/pdf/1505.04969 (dealing with the complementary maximum-independent-set problem) has as a theorem that, for random graphs for which $p = 1/n$, $p$ converges to 0 in such a way that running time is exponential; but I haven't looked at it yet.

clemens‭ wrote 4 months ago

alx‭ "Theorem 3" of that preprint says that running time for random graphs where $p = k/n$ will be at least proportional to $e^{\frac{n}e}$. But my hunch is that optimizations (like yours) can reduce that exponent quite a bit.

alx‭ wrote 4 months ago · edited 4 months ago

clemens‭ Hmmm; very interesting! I understand less from this paper than the other you shared, but still could follow it reasonably. So, it seems to confirm that if p would be constant, it would be subexponential; but p may grow, in which case it's exponential. So, only an optimization that would prevent p from growing (if that is possible at all) would turn it into subexponential.

clemens‭ wrote 4 months ago

@alx Yes; the required optimization would have to prevent $p$ from being inversely proportional to $n$ (in the complementary, max-independent-set problem).

alx‭ wrote 4 months ago · edited 4 months ago

clemens‭, You mention being inversely proportional to n (and the paper too), but what would happen if p decreased slower than inversely proportional to n (in the MIS) but still wasn't constant? For example, if it were inversely proportional to sqrt(n) or log(n)? Would that make it exp or subexp? I think that would remain exp, right?

clemens‭ wrote 4 months ago

@alx: I don't think so; at any rate, my impression is it has to decrease at least as fast as $\frac1n$.

alx‭ wrote 4 months ago · edited 4 months ago

clemens‭ Hmmmm, after replacing p in WolframAlpha, I think you're right that 1/log(n) doesn't remain exponential.

BTW, I'm running at the moment two different experiments. One with random graphs, of sizes 16, 32, 64, and 128. That one seems to show an increase of p for the most expensive random cases, which seems to be of the form 1-1/n. This seems to say that complexity of random graphs grows exponentially.

However, the other experiment seems promising (TBH, once the first test had finished, I was assuming this would also give the same results, but I got some surprise). I slightly tweaked the brute force search I did recently, so that from all equally hard worst cases, I pick the one with smallest p (now that we know that p is key in determining whether it's exponential or QP). It seems p not only doesn't grow, but it actually is decreasing (for the maximum clique, so for MIS it would increase). I'll update when this experiment finishes, in some weeks.

alx‭ wrote 4 months ago

Here's a table of the run times for random graphs. p seems to grow more or less as 1 - C/n for random graphs, which would indicate exponential complexity for random graphs.

n=16	p=0.5	t=0.32s
	p=0.7	t=0.10s
	p=0.75	t=0.11s
	p=0.8	t=0.11s
	p=0.85	t=0.12s
	p=0.9	t=0.16s
	p=0.95	t=0.18s
	p=0.98	t=0.23s
	p=0.99	t=0.23s

n=32	p=0.79	t=1.16s
	p=0.7	t=0.78s
	p=0.75	t=0.71s
	p=0.8	t=0.97s
	p=0.85	t=0.39s
	p=0.9	t=0.47s
	p=0.95	t=0.28s
	p=0.98	t=0.36s
	p=0.99	t=0.43s

n=64	p=0.78	t=17.28s
	p=0.7	t=12.48s
	p=0.75	t=16.10s
	p=0.8	t=14.39s
	p=0.85	t= 9.30s
	p=0.9	t= 3.97s
	p=0.95	t= 0.54s
	p=0.98	t= 0.69s
	p=0.99	t= 0.72s

n=128	p=0.89	t=15189s
	p=0.7	t= 1187s
	p=0.75	t= 2374s
	p=0.8	t= 6780s
	p=0.85	t=12859s
	p=0.9	t=13800s
	p=0.95	t=  693s
	p=0.98	t=    2s
	p=0.99	t=    1s

(But as noted before, I'm running another similar experiment with the worst cases (found with brute force), which seems to hint a different trend.)

alx‭ wrote about 2 months ago · edited about 2 months ago

I've been improving the algorithm as I found worst cases that were obviously easy. After that, the most difficult worst cases remained, and those indeed have a growing p. It doesn't seem to grow as fast as 1-1/n in the worst cases, but it grows, and it might be just an artifact of small numbers that it doesn't resemble 1-1/n.

The worst average case indeed seems to grow as 1-1/n, and since the average case can't be worse than the worst case, this seems to be evidence that it's exponential.