Finde die kürzesten Golomb-Herrscher

15

Golomb-Lineale sind Mengen nicht negativer Ganzzahlen, sodass keine zwei Paare von Ganzzahlen in der Menge den gleichen Abstand voneinander haben.

Ist beispielsweise [0, 1, 4, 6]ein Golomb-Lineal, weil alle Abstände zwischen zwei Ganzzahlen in dieser Menge eindeutig sind:

0, 1 -> distance 1
0, 4 -> distance 4
0, 6 -> distance 6
1, 4 -> distance 3
1, 6 -> distance 5
4, 6 -> distance 2

Der Einfachheit halber wird bei dieser Herausforderung (und da die Übersetzung trivial ist) vorausgesetzt , dass ein Golomb-Lineal immer die Zahl enthält0 (wie im vorherigen Beispiel).

Da diese Menge von Länge ist 4, sagen wir, dass dies ein Golomb-Lineal der Ordnung ist 4 . Der größte Abstand in dieser Menge (oder Element, da 0immer in der Menge) ist 6, sagen wir daher, dass dies ein Golomb-Lineal der Länge ist 6 .

Deine Aufgabe

Finden Golomb Herrscher , um 50 zu 100(einschließlich) , die so klein haben Längen , wie Sie finden können. Die gefundenen Lineale müssen nicht optimal sein (siehe unten).

Optimalität

Ein Golomb-Ordnungslineal Ngilt als optimal, wenn es kein anderes Golomb-Ordnungslineal Nmit geringerer Länge gibt.

Optimale Golomb-Lineale sind für Befehle unter 28 bekannt , obwohl es mit zunehmender Reihenfolge immer schwieriger wird, Optimalität zu finden und zu beweisen.

Daher wird nicht erwartet, dass Sie das optimale Golomb-Lineal für eine der Anweisungen zwischen 50und finden 100(und noch weniger erwartet, dass Sie nachweisen können, dass sie optimal sind).

Die Ausführung Ihres Programms ist zeitlich unbegrenzt.

Grundlinie

Die folgende Liste enthält die Längen der Golomb-Lineale von 50bis 100(in der Reihenfolge), die mit einer naiven Suchstrategie ausgewertet wurden (Dank an @PeterTaylor für diese Liste):

[4850 5122 5242 5297 5750 5997 6373 6800 6924 7459 7546 7788 8219 8502 8729 8941 9881 10199 10586 10897 11288 11613 11875 12033 12930 13393 14046 14533 14900 15165 15687 15971 16618 17354 17931 18844 19070 19630 19669 20721 21947 22525 23290 23563 23880 24595 24767 25630 26036 26254 27218]

Die Summe all dieser Längen ist 734078.

Wertung

Ihre Punktzahl ist die Summe der Längen aller Ihren Golomb Herrschers zwischen 50und 100geteilt durch die Summe der Längen von Golomb Herrschern zwischen 50und 100in der Basislinie: 734078.

Falls Sie für eine bestimmte Reihenfolge kein Golomb-Lineal gefunden haben, berechnen Sie Ihre Punktzahl auf die gleiche Weise, indem Sie das Doppelte der Länge in der Grundlinie für diese bestimmte Reihenfolge verwenden.

Die Antwort mit der niedrigsten Punktzahl gewinnt.

Im Falle eines Gleichstands werden die Längen der größten Bestellung verglichen, bei denen sich die beiden Antworten unterscheiden, und die kürzeste gewinnt. Wenn beide Antworten für alle Bestellungen gleich lang sind, gewinnt die Antwort, die zuerst gesendet wurde.

Tödlich
quelle
2
Verbunden. (Gleiche Herausforderung in 2D.)
Martin Ender
Und OEIS-Eintrag .
Martin Ender
Wenn Sie Lineale zwischen 50 und 100 sagen, meinen Sie den Bereich [50, 100]? Also ohne die Bestellung 100 Lineal? Weil die Grundlinie nur 50 Elemente enthält.
Orlp
1
Randnotiz: Die kleinstmögliche Länge eines Golomb-Ordnungslineals nist n(n-1)/2, da es so viele positive Unterschiede gibt. Daher ist die kleinstmögliche Punktzahl bei dieser Herausforderung 147050/734078 > 0.2003193.
Greg Martin
2
@ GregMartin Danke, obwohl dies nicht ganz die "kleinstmögliche Punktzahl" ist, sondern eine Untergrenze für die kleinstmögliche Punktzahl!
Fatalize

Antworten:

8

C #, 259421/734078 ~ = 0,3534

Methoden

Ich habe schließlich eine mehr oder weniger lesbare Erklärung für die projektive Feldmethode (Singers Methode) in Konstruktionen verallgemeinerter Sidon-Mengen gefunden , obwohl ich immer noch denke, dass sie leicht verbessert werden kann. Es stellt sich heraus, dass es der Affinen-Feld-Methode (Bose-Methode) ähnlicher ist als die anderen Artikel, die ich gelesen habe.

q=peinF(q)

F(q2)G2F(q2)kF(q)

{ein:G2ein-kG2Fq}
q2-1q2-1

F(q3)G3F(q3)kF(q)

{0}{ein:G3ein-kG3Fq}
q2+q+1

Beachten Sie, dass diese Methoden die bekanntesten Werte für jede Länge größer als 16 ergeben. Tomas Rokicki und Gil Dogon bieten eine Belohnung von 250 USD für jeden, der sie für Längen von 36 bis 40000 schlägt Preis.

Code

Das C # ist nicht sehr idiomatisch, aber ich brauche es, um mit einer alten Version von Mono zu kompilieren. Dies ist trotz der Überprüfung der Argumente kein Qualitätscode für die Produktion. Ich bin mit den Typen nicht zufrieden, aber ich glaube nicht, dass es in C # eine wirklich gute Lösung dafür gibt. Vielleicht in F # oder C ++ mit verrückten Vorlagen.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sandbox {
    class Program {
        static void Main(string[] args) {
            var winners = ComputeRulerRange(50, 100);
            int total = 0;
            for (int i = 50; i <= 100; i++) {
                Console.WriteLine("{0}:\t{1}", i, winners[i][i - 1]);
                total += winners[i][i - 1];
            }
            Console.WriteLine("\t{0}", total);
        }

        static IDictionary<int, int[]> ComputeRulerRange(int min, int max) {
            var best = new Dictionary<int, int[]>();

            var naive = Naive(max);
            for (int i = min; i <= max; i++) best[i] = naive.Take(i).ToArray();

            var finiteFields = FiniteFields(max * 11 / 10).OrderBy(x => x.Size).ToArray();

            // The projective plane method generates rulers of length p^a + 1 for prime powers p^a.
            // We can then look at subrulers for a reasonable range, say down to two prime powers below.
            for (int ppi = 0; ppi < finiteFields.Length; ppi++) {
                // Range under consideration
                var field = finiteFields[ppi];
                int q = field.Size;
                int subFrom = Math.Max(min, ppi >= 2 ? finiteFields[ppi - 2].Size : 1);
                int subTo = Math.Min(max, q + 1);
                if (subTo < subFrom) continue;

                int m = q * q + q + 1;
                foreach (var ruler in ProjectiveRulers(field)) {
                    for (int sub = subFrom; sub <= subTo; sub++) {
                        var subruler = BestSubruler(ruler, sub, m);
                        if (subruler[sub - 1] < best[sub][sub - 1]) best[sub] = subruler;
                    }
                }
            }

            // Similarly for the affine plane method, which generates rulers of length p^a for prime powers p^a
            for (int ppi = 0; ppi < finiteFields.Length; ppi++) {
                // Range under consideration
                var field = finiteFields[ppi];
                int q = field.Size;
                int subFrom = Math.Max(min, ppi >= 2 ? finiteFields[ppi - 2].Size : 1);
                int subTo = Math.Min(max, q);
                if (subTo < subFrom) continue;

                int m = q * q - 1;
                foreach (var ruler in AffineRulers(field)) {
                    for (int sub = subFrom; sub <= subTo; sub++) {
                        var subruler = BestSubruler(ruler, sub, m);
                        if (subruler[sub - 1] < best[sub][sub - 1]) best[sub] = subruler;
                    }
                }
            }

            return best;
        }

        static int[] BestSubruler(int[] ruler, int sub, int m) {
            int[] expand = new int[ruler.Length + sub - 1];
            for (int i = 0; i < ruler.Length; i++) expand[i] = ruler[i];
            for (int i = 0; i < sub - 1; i++) expand[ruler.Length + i] = ruler[i] + m;

            int best = m, bestIdx = -1;
            for (int i = 0; i < ruler.Length; i++) {
                if (expand[i + sub - 1] - expand[i] < best) {
                    best = expand[i + sub - 1] - expand[i];
                    bestIdx = i;
                }
            }

            return expand.Skip(bestIdx).Take(sub).Select(x => x - ruler[bestIdx]).ToArray();
        }

        static IEnumerable<int[]> ProjectiveRulers(FiniteField field) {
            var q = field.Size;
            var fq3 = PowerField.Create(field, 3);
            var m = q * q + q + 1;
            var g = fq3.Generators.First();

            // Define the set T<k> = {0} \union {a \in [q^3-1] : g^a - kg \in F(q)} for 0 != k \in F(q)
            // This could alternatively be T<k> = {0} \union {log_g(b - kg) : b in F(q)} for 0 != k \in F(q)
            // Then T<k> % (q^2 + q + 1) gives a Golomb ruler.
            // For a given generator we seem to get the same ruler for every k.
            var t_k = new HashSet<int>();
            t_k.Add(0);
            var ga = fq3.One;
            for (int a = 1; a < fq3.Size; a++) {
                ga = ga * g;
                if (fq3.Convert(ga + g) < q) t_k.Add(a % m);
            }

            // TODO: optimise by detecting duplicates
            for (int s = 1; s < m; s++) {
                if (Gcd(s, m) == 1) yield return t_k.Select(x => x * s % m).OrderBy(x => x).ToArray();
            }
        }

        static IEnumerable<int[]> AffineRulers(FiniteField field) {
            var q = field.Size;
            var fq2 = PowerField.Create(field, 2);
            var m = q * q - 1;
            var g = fq2.Generators.First();

            // Define the set T<k> = {0} \union {a \in [q^2-1] : g^a - kg \in F(q)} for 0 != k \in F(q)
            // Then T<k> % (q^2 - 1) gives a Golomb ruler.
            var t_k = new HashSet<int>();
            var ga = fq2.One;
            for (int a = 1; a < fq2.Size; a++) {
                ga = ga * g;
                if (fq2.Convert(ga + g) < q) t_k.Add(a % m);
            }

            // TODO: optimise by detecting duplicates
            for (int s = 1; s < m; s++) {
                if (Gcd(s, m) == 1) yield return t_k.Select(x => x * s % m).OrderBy(x => x).ToArray();
            }
        }

        static int Gcd(int a, int b) {
            while (a != 0) {
                var t = b % a;
                b = a;
                a = t;
            }

            return b;
        }

        static int[] Naive(int size) {
            if (size == 0) return new int[0];
            if (size == 1) return new int[] { 0 };

            int[] ruler = new int[size];
            var diffs = new HashSet<int>();
            int i = 1, c = 1;
            while (true) {
                bool valid = true;
                for (int j = 0; j < i; j++) {
                    if (diffs.Contains(c - ruler[j])) { valid = false; break; }
                }

                if (valid) {
                    for (int j = 0; j < i; j++) diffs.Add(c - ruler[j]);
                    ruler[i++] = c;
                    if (i == size) return ruler;
                }

                c++;
            }
        }

        static IEnumerable<FiniteField> FiniteFields(int max) {
            bool[] isComposite = new bool[max + 1];
            for (int p = 2; p < isComposite.Length; p++) {
                if (!isComposite[p]) {
                     FiniteField baseField = new PrimeField(p); yield return baseField;
                    for (int pp = p * p, pow = 2; pp < max; pp *= p, pow++) yield return PowerField.Create(baseField, pow);
                    for (int pq = p * p; pq <= max; pq += p) isComposite[pq] = true;
                }
            }
        }
    }

    public abstract class FiniteField {
        private Lazy<FiniteFieldElement> _Zero;
        private Lazy<FiniteFieldElement> _One;

        public FiniteFieldElement Zero { get { return _Zero.Value; } }
        public FiniteFieldElement One { get { return _One.Value; } }
        public IEnumerable<FiniteFieldElement> Generators {
            get {
                for (int _g = 1; _g < Size; _g++) {
                    int pow = 0;
                    FiniteFieldElement g = Convert(_g), gpow = One;
                    while (true) {
                        pow++;
                        gpow = gpow * g;
                        if (gpow == One) break;
                        if (pow > Size) {
                            throw new Exception("Is this really a field? " + this);
                        }
                    }
                    if (pow == Size - 1) yield return g;
                }
            }
        }

        public abstract int Size { get; }
        internal abstract FiniteFieldElement Convert(int i);
        internal abstract int Convert(FiniteFieldElement f);

        internal abstract bool Eq(FiniteFieldElement a, FiniteFieldElement b);
        internal abstract FiniteFieldElement Negate(FiniteFieldElement a);
        internal abstract FiniteFieldElement Add(FiniteFieldElement a, FiniteFieldElement b);
        internal abstract FiniteFieldElement Mul(FiniteFieldElement a, FiniteFieldElement b);

        protected FiniteField() {
            _Zero = new Lazy<FiniteFieldElement>(() => Convert(0));
            _One = new Lazy<FiniteFieldElement>(() => Convert(1));
        }
    }

    public abstract class FiniteFieldElement {
        internal abstract FiniteField Field { get; }

        public static FiniteFieldElement operator -(FiniteFieldElement a) {
            return a.Field.Negate(a);
        }

        public static FiniteFieldElement operator +(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != b.Field) throw new ArgumentOutOfRangeException("b");
            return a.Field.Add(a, b);
        }

        public static FiniteFieldElement operator *(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != b.Field) throw new ArgumentOutOfRangeException("b");
            return a.Field.Mul(a, b);
        }

        public static bool operator ==(FiniteFieldElement a, FiniteFieldElement b) {
            if (Equals(a, null)) return Equals(b, null);
            else if (Equals(b, null)) return false;

            if (a.Field != b.Field) throw new ArgumentOutOfRangeException("b");
            return a.Field.Eq(a, b);
        }

        public static bool operator !=(FiniteFieldElement a, FiniteFieldElement b) { return !(a == b); }

        public override bool Equals(object obj) {
            return (obj is FiniteFieldElement) && (obj as FiniteFieldElement).Field == Field && this == (obj as FiniteFieldElement);
        }

        public override int GetHashCode() { return Field.Convert(this).GetHashCode(); }

        public override string ToString() { return Field.Convert(this).ToString(); }
    }

    public class PrimeField : FiniteField {
        private readonly int _Prime;
        private readonly PrimeFieldElement[] _Featherweight;

        internal int Prime { get { return _Prime; } }
        public override int Size { get { return _Prime; } }

        public PrimeField(int prime) {
            if (prime < 2) throw new ArgumentOutOfRangeException("prime");

            // TODO A primality test would be nice...

            _Prime = prime;
            _Featherweight = new PrimeFieldElement[Math.Min(prime, 256)];
        }

        internal override FiniteFieldElement Convert(int i) {
            if (i < 0 || i >= _Prime) throw new ArgumentOutOfRangeException("i");
            if (i >= _Featherweight.Length) return new PrimeFieldElement(this, i);
            if (Equals(_Featherweight[i], null)) _Featherweight[i] = new PrimeFieldElement(this, i);
            return _Featherweight[i];
        }

        internal override int Convert(FiniteFieldElement f) {
            if (f == null) throw new ArgumentNullException("f");
            if (f.Field != this) throw new ArgumentOutOfRangeException("f");

            return (f as PrimeFieldElement).Value;
        }

        internal override bool Eq(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            return (a as PrimeFieldElement).Value == (b as PrimeFieldElement).Value;
        }

        internal override FiniteFieldElement Negate(FiniteFieldElement a) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            var fa = a as PrimeFieldElement;
            return fa.Value == 0 ? fa : Convert(_Prime - fa.Value);
        }

        internal override FiniteFieldElement Add(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            return Convert(((a as PrimeFieldElement).Value + (b as PrimeFieldElement).Value) % _Prime);
        }

        internal override FiniteFieldElement Mul(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            return Convert(((a as PrimeFieldElement).Value * (b as PrimeFieldElement).Value) % _Prime);
        }

        public override string ToString() { return string.Format("F({0})", _Prime); }
    }

    internal class PrimeFieldElement : FiniteFieldElement {
        private readonly PrimeField _Field;
        private readonly int _Value;

        internal override FiniteField Field { get { return _Field; } }
        internal int Value { get { return _Value; } }

        internal PrimeFieldElement(PrimeField field, int val) {
            if (field == null) throw new ArgumentNullException("field");
            if (val < 0 || val >= field.Prime) throw new ArgumentOutOfRangeException("val");

            _Field = field;
            _Value = val;
        }
    }

    public class PowerField : FiniteField {
        private readonly FiniteField _BaseField;
        private readonly FiniteFieldElement[] _Polynomial;

        internal FiniteField BaseField { get { return _BaseField; } }
        internal int Power { get { return _Polynomial.Length; } }
        public override int Size { get { return (int)Math.Pow(_BaseField.Size, Power); } }

        public PowerField(FiniteField baseField, FiniteFieldElement[] polynomial) {
            if (baseField == null) throw new ArgumentNullException("baseField");
            if (polynomial == null) throw new ArgumentNullException("polynomial");
            if (polynomial.Length < 2) throw new ArgumentOutOfRangeException("polynomial");
            for (int i = 0; i < polynomial.Length; i++) if (polynomial[i].Field != baseField) throw new ArgumentOutOfRangeException("polynomial[" + i + "]");

            // TODO Check that the polynomial is irreducible over the base field.

            _BaseField = baseField;
            _Polynomial = polynomial.ToArray();
        }

        internal override FiniteFieldElement Convert(int i) {
            if (i < 0 || i >= Size) throw new ArgumentOutOfRangeException("i");

            var vec = new FiniteFieldElement[Power];
            for (int j = 0; j < vec.Length; j++) {
                vec[j] = BaseField.Convert(i % BaseField.Size);
                i /= BaseField.Size;
            }

            return new PowerFieldElement(this, vec);
        }

        internal override int Convert(FiniteFieldElement f) {
            if (f == null) throw new ArgumentNullException("f");
            if (f.Field != this) throw new ArgumentOutOfRangeException("f");

            var pf = f as PowerFieldElement;
            int i = 0;
            for (int j = Power - 1; j >= 0; j--) i = i * BaseField.Size + BaseField.Convert(pf.Value[j]);
            return i;
        }

        internal override bool Eq(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            var fa = a as PowerFieldElement;
            var fb = b as PowerFieldElement;
            for (int i = 0; i < Power; i++) if (fa.Value[i] != fb.Value[i]) return false;
            return true;
        }

        internal override FiniteFieldElement Negate(FiniteFieldElement a) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            return new PowerFieldElement(this, (a as PowerFieldElement).Value.Select(x => -x).ToArray());
        }

        internal override FiniteFieldElement Add(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            var fa = a as PowerFieldElement;
            var fb = b as PowerFieldElement;
            var vec = new FiniteFieldElement[Power];
            for (int i = 0; i < Power; i++) vec[i] = fa.Value[i] + fb.Value[i];
            return new PowerFieldElement(this, vec);
        }

        internal override FiniteFieldElement Mul(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            var fa = a as PowerFieldElement;
            var fb = b as PowerFieldElement;

            // We consider fa and fb as polynomials of a variable x and multiply modulo (x^Power - _Polynomial).
            // But to keep things simple we want to manage the cascading modulo.
            var vec = Enumerable.Repeat(BaseField.Zero, Power).ToArray();
            var fa_xi = fa.Value.ToArray();
            for (int i = 0; i < Power; i++) {
                for (int j = 0; j < Power; j++) vec[j] += fb.Value[i] * fa_xi[j];
                if (i < Power - 1) ShiftLeft(fa_xi);
            }

            return new PowerFieldElement(this, vec);
        }

        private void ShiftLeft(FiniteFieldElement[] vec) {
            FiniteFieldElement head = vec[vec.Length - 1];
            for (int i = vec.Length - 1; i > 0; i--) vec[i] = vec[i - 1] + head * _Polynomial[i];
            vec[0] = head * _Polynomial[0];
        }

        public static FiniteField Create(FiniteField baseField, int power) {
            if (baseField == null) throw new ArgumentNullException("baseField");
            if (power < 2) throw new ArgumentOutOfRangeException("power");

            // Since the field is cyclic, there is only one finite field of a given prime power order (up to isomorphism).
            // For most practical purposes that means that we can pick any arbitrary monic irreducible polynomial.
            // We can abuse PowerField to do polynomial multiplication in the base field.
            var fakeField = new PowerField(baseField, Enumerable.Repeat(baseField.Zero, power).ToArray());
            var excluded = new HashSet<FiniteFieldElement>();
            for (int lpow = 1; lpow <= power / 2; lpow++) {
                int upow = power - lpow;
                // Consider all products of a monic polynomial of order lpow with a monic polynomial of order upow.
                int xl = (int)Math.Pow(baseField.Size, lpow);
                int xu = (int)Math.Pow(baseField.Size, upow);
                for (int i = xl; i < 2 * xl; i++) {
                    var pi = fakeField.Convert(i);
                    for (int j = xu; j < 2 * xu; j++) {
                        var pj = fakeField.Convert(j);
                        excluded.Add(-(pi * pj));
                    }
                }
            }

            for (int p = baseField.Size; true; p++) {
                var pp = fakeField.Convert(p) as PowerFieldElement;
                if (!excluded.Contains(pp)) return new PowerField(baseField, pp.Value.ToArray());
            }
        }

        public override string ToString() {
            var sb = new System.Text.StringBuilder();
            sb.AppendFormat("GF({0}) with primitive polynomial x^{1} ", Size, Power);
            for (int i = Power - 1; i >= 0; i--) sb.AppendFormat("+ {0}x^{1}", _Polynomial[i], i);
            sb.AppendFormat(" over base field ");
            sb.Append(_BaseField);
            return sb.ToString();
        }
    }

    internal class PowerFieldElement : FiniteFieldElement {
        private readonly PowerField _Field;
        private readonly FiniteFieldElement[] _Vector; // The version of Mono I have doesn't include IReadOnlyList<T>

        internal override FiniteField Field { get { return _Field; } }
        internal FiniteFieldElement[] Value { get { return _Vector; } }

        internal PowerFieldElement(PowerField field, params FiniteFieldElement[] vector) {
            if (field == null) throw new ArgumentNullException("field");
            if (vector == null) throw new ArgumentNullException("vector");
            if (vector.Length != field.Power) throw new ArgumentOutOfRangeException("vector");
            for (int i = 0; i < vector.Length; i++) if (vector[i].Field != field.BaseField) throw new ArgumentOutOfRangeException("vector[" + i + "]");

            _Field = field;
            _Vector = vector.ToArray();
        }
    }
}

Ergebnisse

Leider würde das Hinzufügen der Lineale etwa 15.000 Zeichen nach dem Post-Größenlimit erfordern, sodass sie im Pastebin sind .

Peter Taylor
quelle
Würdest du so freundlich sein, deine Lineale für [50, 100] irgendwo zu posten? Ich habe einen genetischen Algorithmus, den ich ausprobieren möchte und der einige Samenwerte liefert.
Orlp
@orlp, hat einen Link hinzugefügt.
Peter Taylor
2
Wie ich vermutet habe, kann der Evolutionsalgorithmus nichts Nützliches aus diesen überlegenen Exemplaren extrahieren. Auch wenn es anfangs so aussah, als ob evolutionäre Algorithmen funktionieren könnten (sie wandeln sich so ziemlich augenblicklich von ungültigen zu tatsächlichen Herrschern), ist zu viel globale Struktur erforderlich, damit der evolutionäre Algorithmus funktioniert.
Orlp
5

Python 3, Punktzahl 603001/734078 = 0,82144

Naive Suche kombiniert mit Erdős-Turan-Konstruktion:

2pk+(k2modp),k[0,p-1]

Für ungerade Primzahlen p ergibt sich ein asymptotisch optimales Golomb-Lineal.

def isprime(n):
    if n < 2: return False
    if n % 2 == 0: return n == 2
    k = 3
    while k*k <= n:
         if n % k == 0: return False
         k += 2
    return True

rulers = []
ruler = []
d = set()
n = 0
while len(ruler) <= 100:
    order = len(ruler) + 1
    if order > 2 and isprime(order):
        ruler = [2*order*k + k*k%order for k in range(order)]
        d = {a-b for a in ruler for b in ruler if a > b}
        n = max(ruler) + 1
        rulers.append(tuple(ruler))
        continue

    nd = set(n-e for e in ruler)
    if not d & nd:
        ruler.append(n)
        d |= nd
        rulers.append(tuple(ruler))
    n += 1


isuniq = lambda l: len(l) == len(set(l))
isruler = lambda l: isuniq([a-b for a in l for b in l if a > b])

assert all(isruler(r) for r in rulers)

rulers = list(sorted([r for r in rulers if 50 <= len(r) <= 100], key=len))
print(sum(max(r) for r in rulers))
orlp
quelle
Ich denke nicht, dass diese Konstruktion asymptotisch optimal ist: Sie ergibt ein Golomb-Lineal von pungefähr der Ordnung und Länge 2p^2, während es Golomb-Lineale von nungefähr der Ordnung und Länge n^2asymptotisch gibt.
Greg Martin
@ GregMartin Asymptotisch gibt es keinen Unterschied zwischen 2p^2und p^2.
Orlp
Kommt auf deine Definition von "asymptotisch" an, denke ich, aber für mich sind sie in diesem Zusammenhang sehr unterschiedlich.
Greg Martin
3

Mathematica, Punktzahl 276235/734078 <0,376302

ruzsa[p_, i_] := Module[{g = PrimitiveRoot[p]},
  Table[ChineseRemainder[{t, i PowerMod[g, t, p]}, {p - 1, p}], {t, 1, p - 1}] ]

reducedResidues[m_] := Select[Range@m, CoprimeQ[m, #] &]

rotate[set_, m_] := Mod[set - #, m] & /@ set

scaledRuzsa[p_] := Union @@ Table[ Sort@Mod[a b, p (p - 1)],
  {a, reducedResidues[p (p - 1)]}, {b, rotate[ruzsa[p, 1], p (p - 1)]}]

manyRuzsaSets = Join @@ Table[scaledRuzsa[Prime[n]], {n, 32}];

tryGolomb[set_, k_] := If[Length[set] < k, Nothing, Take[set, k]]

Table[First@MinimalBy[tryGolomb[#, k] & /@ manyRuzsaSets, Max], {k, 50, 100}]

Die Funktion ruzsaimplementiert eine Konstruktion eines Golobm-Lineals (auch Sidon-Set genannt), das sich in Imre Z. Ruzsa befindet. Lösen einer linearen Gleichung in einer Menge von ganzen Zahlen. I. Acta Arith., 65 (3): 259–282, 1993 . Bei jeder Primzahl pergibt diese Konstruktion ein Golomb-Lineal mit p-1Elementen, die in den Ganzzahlen modulo enthalten sind p(p-1)(dies ist eine noch stärkere Bedingung als ein Golomb-Lineal in den Ganzzahlen selbst).

Ein weiterer Vorteil der Arbeit im Ganzzahlmodulo mbesteht darin, dass jedes Golomb-Lineal gedreht (die gleiche Konstante wird zu allen Modulo-Elementen hinzugefügt m) und skaliert werden kann (alle Elemente werden mit der gleichen Konstante multipliziert, solange diese Konstante relativ hoch ist m) das Ergebnis ist immer noch ein Golomb-Herrscher; manchmal wird dadurch die größte ganze Zahl signifikant verringert. Die Funktion scaledRuzsaversucht alle diese Skalierungen und zeichnet die Ergebnisse auf. manyRuzsaSetsenthält die Ergebnisse dieser Konstruktion und Skalierung für alle ersten 32 Primzahlen (etwas willkürlich gewählt, aber die 32. Primzahl 131 ist deutlich größer als 100); Es gibt fast 57.000 Golomb-Lineale in diesem Satz, was einige Minuten in Anspruch nimmt.

Natürlich bilden die ersten kElemente eines Golomb-Lineals selbst ein Golomb-Lineal. Die Funktion tryGolombbetrachtet also ein solches Lineal, das aus einer der oben berechneten Mengen besteht. Die letzte Zeile Table...wählt die beste Golomb Herrscher kann es, von jeder Bestellung von 50zu 100, von allen Golomb - Maßstäbe auf diese Weise gefunden.

Die gefundenen Längen waren:

{2241, 2325, 2399, 2578, 2640, 2762, 2833, 2961, 3071, 3151, 3194, 3480, 3533, 3612, 3775, 3917, 4038, 4150, 4237, 4368, 4481, 4563, 4729, 4974, 5111, 5155, 5297, 5504, 5583, 5707, 5839, 6077, 6229, 6480, 6611, 6672, 6913, 6946, 7025, 7694, 7757, 7812, 7969, 8139, 8346, 8407, 8678, 8693, 9028, 9215, 9336}

Ich wollte das ursprünglich mit zwei anderen Konstruktionen kombinieren, denen von Singer und Bose; aber es scheint, dass Peter Taylors Antwort dies bereits umgesetzt hat, so dass ich diese Längen vermutlich einfach wiedererlangen würde.

Greg Martin
quelle
Ich bin durch Ihre Behauptung verwirrt, dass Sie bei der Arbeit im Ganzzahlmodul mfrei drehen / skalieren können. Schau dir [0, 1, 4, 6]Mod 7 an. Wenn ich 1 hinzufüge, bekommen wir [0, 1, 2, 5], was kein Golomb-Lineal ist.
Orlp
Das liegt daran, dass Sie mit einem Golomb-Lineal der Modifikation 7 beginnen müssen, damit es funktioniert. [0, 1, 4, 6]ist kein mod-7 Golomb-Lineal, weil es zum Beispiel 1 – 0gleich 0 – 6modulo 7 ist.
Greg Martin
1
Während ich meine Finite-Felder-Implementierung in C # schrieb und debuggte, wünschte ich mir, ich würde Mathematica besser kennen. Auf jeden Fall eine der richtigen Sprachen für den Job.
Peter Taylor