Can you Meta Quine?

Python, 0 (limit of (68+3 n )/(16n))

If two abstract syntax trees are different if they have different constants,

r='r=%r;n=(0x%XL+1)%%0x10...0L;print r%%(r,n)';n=(0xF...FL+1)%0x10...0L;print r%(r,n)

there are 16n programs of length at most 68+3n, giving asymptotic score of 0.

If you want programs with variable structure, we can implement a binary adder on n bits. Here, there are 2n programs of length O( n2). Goes in a cycle due to dropped carry bit.

s="""
print 's='+'"'+'"'+'"'+s+'"'+'"'+'"'
n=lambda m:reduce(lambda (s,c),y:(s+(c^y,),c&y),m,((),1))[0]
print s[:112]
t=n(t)
print "t=(%s,)+(0,)*%s"%(t[0],len(t)-1)
for i in range(len(t)-1):
    print i*' '+'for i in range(2):'
    print ' '+i*' '+['pass','t=n(t)'][t[i+1]]
print s[113:-1]
"""

print 's='+'"'+'"'+'"'+s+'"'+'"'+'"'
n=lambda m:reduce(lambda (s,c),y:(s+(c^y,),c&y),m,((),1))[0]
print s[:112]
t=(0,)+(0,)*10
for i in range(2):
 t=n(t)
 for i in range(2):
  t=n(t)
  for i in range(2):
   t=n(t)
   for i in range(2):
    t=n(t)
    for i in range(2):
     pass
     for i in range(2):
      t=n(t)
      for i in range(2):
       pass
       for i in range(2):
        pass
        for i in range(2):
         pass
         for i in range(2):
          t=n(t)
t=n(t)
print "t=(%s,)+(0,)*%s"%(t[0],len(t)-1)
for i in range(len(t)-1):
    print i*' '+'for i in range(2):'
    print ' '+i*' '+['pass','t=n(t)'][t[i+1]]
print s[113:-1]

C++, score of 0.734194

The following source code prints a meta quine of order 999 to the console (explanation below):

#define X 1*(1+1)
#include<iostream>
#include<vector>
#define Q(S)auto q=#S;S
Q( \
  main() \
  { \
      using namespace std; \
      cout<<"#define X 1"; \
      int x=X==2?1000:X-1; \
      vector<int> factors; \
      for ( int p = 2; p <= x; ++p) \
      { \
        while ( x % p == 0 ) \
        { \
          factors.push_back( p ); \
          x /= p; \
        } \
      } \
      for ( int factor : factors ) \
      { \
        cout<<"*(1"; \
        for ( int i=1;i<factor;++i) \
          cout<<"+1"; \
        cout<<")"; \
      } \
      cout<<"\n#include<iostream>\n#include<vector>\n#define Q(S)auto q=#S;S\nQ("<<q<<")"; \
  })

The only line that changes is the first line. The value of X will be 1000, 999, 998, ..., 3, 2 and then it will start again. However, in order to get different syntax trees every time, X is represented in terms of its prime factorization, where every prime is written as a sum of 1s. The ASTs are different, because the prime factorization of integers is different for every value.

The program will print itself, except that the first line is changed and the backslashes, line breaks and indentations that are within Q(...) will be removed.

The following program calculates the score of my answer:

#include <iostream>

const int n = 1000;

int getProgramLength( int n )
{
  int sum = 442;
  for ( int p = 2; p*p <= n; ++p )
  {
    while ( n % p == 0 )
    {
      sum += 2 * ( 1 + p );
      n /= p;
    }
  }
  if ( n > 1 )
    sum += 2 * ( 1 + n );
  return sum;
}

int main()
{
  int sum = 0;
  for ( int i = 2; i <= n; ++i )
    sum += getProgramLength( i );
  std::cout << (double)sum/(n-1)/(n-1) << '\n';
}

It printed 0.734194 to the console. Obviously, 1000 can be replaced by larger integers and the score will approach 0 as its limit. The mathematical proof involves Riemann's Zeta function is somewhat convoluted. I leave it as an exercise to the reader. ;)


Perl, score of 110.25

I have to admit, I'm not very good with quines. I'm 100% certain that there is room for improvement. The solution is based off of the same principle of the Element solution below.

The first program is 264 characters.

$s='$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}';$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}

The second program is 177 characters.

$s='$a=chr(39);print"\$s=$a$s$a;";$s=reverse$s;for(1..87){chop$s}$s=reverse$s;print$s;$f++;if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}';if($f==0){$a=chr(39);print"\$s=$a$s$a;$s"}

I'm working on the AST for this entry (and the Element entry).


Element, score of 47.25

The first program is 105 characters.

\ \3\:\$\'\[\\\\\`\(\`\]\#\2\1\'\[\(\#\]\`\ \3\:\$\'\[\\\\\`\(\`\]\#\` 3:$'[\\`(`]#21'[(#]` 3:$'[\\`(`]#`

The second program is 84 characters.

\ \3\:\$\'\[\\\\\`\(\`\]\#\2\1\'\[\(\#\]\`\ \3\:\$\'\[\\\\\`\(\`\]\#\` 3:$'[\\`(`]#`

I'm sure that there is a lot of room for improvement.

In the first program there is one string (in which every character is escaped, despite a lot of redundancy) followed by executable parts A and B. Part A does several things: prints the string and escapes out of every character, prints the last half of the string (which is the source for part B), and then prevents the part B that follows it from doing anything.

The second program is the same string followed by part B. Part B is based off of a simple quine; it prints a string preceded by an escaped version of it. This means it prints the string, and both parts A and B.