Matrixeigenschaft X überarbeitet (oder die Freude an X)

11

Diese Herausforderung ist teils eine Herausforderung für Algorithmen, teils eine Herausforderung für die Optimierung und teils einfach eine Herausforderung für den schnellsten Code.

Die AT-Matrix wird vollständig durch ihre erste Zeile rund erste Spalte spezifiziert c. Jedes verbleibende Element der Matrix ist nur eine Kopie des Elements, das diagonal nach oben und links zeigt. Das ist M[i,j] = M[i-1,j-1]. Wir werden T-Matrizen zulassen, die nicht quadratisch sind. Wir gehen jedoch immer davon aus, dass die Anzahl der Zeilen nicht größer als die Anzahl der Spalten ist. Betrachten Sie beispielsweise die folgende 3 x 5 T-Matrix.

10111
11011
11101

Wir sagen, eine Matrix hat die Eigenschaft X, wenn sie zwei nicht leere Sätze von Spalten mit nicht identischen Indizes enthält, die dieselbe (Vektor-) Summe haben. Die Vektorsumme einer oder mehrerer Spalten ist einfach eine elementweise Summierung ihrer Spalten. Das ist die Summe von zwei oder mehr Spalten, die xElemente enthalten. Jede ist eine andere Spalte, die xElemente enthält. Die Summe einer Spalte ist trivial die Spalte selbst.

Die obige Matrix hat trivialerweise die Eigenschaft X, da die erste und die letzte Spalte gleich sind. Die Identitätsmatrix hat niemals die Eigenschaft X.

Wenn wir nur die letzte Spalte der obigen Matrix entfernen, erhalten wir ein Beispiel, das keine Eigenschaft X hat und eine Punktzahl von 4/3 ergibt.

1011
1101
1110

Die Aufgabe

Die Aufgabe besteht darin, Code zu schreiben, um die T-Matrix mit der höchsten Punktzahl mit binären Einträgen zu finden, die keine Eigenschaft X hat. Aus Gründen der Klarheit hat eine Matrix mit binären Einträgen die Eigenschaft, dass jeder ihrer Einträge entweder 0 oder 1 ist.

Ergebnis

Ihre Punktzahl besteht aus den Zahlenspalten geteilt durch die Anzahl der Zeilen in Ihrer besten Bewertungsmatrix.

Tie Breaker

Wenn zwei Antworten die gleiche Punktzahl haben, gewinnt die zuerst eingereichte.

In dem (sehr) unwahrscheinlichen Fall, dass jemand eine Methode findet, um unbegrenzte Punktzahlen zu erhalten, wird der erste gültige Beweis für eine solche Lösung akzeptiert. Für den noch unwahrscheinlicheren Fall, dass Sie einen Beweis für die Optimalität einer endlichen Matrix finden, werde ich natürlich auch den Gewinn vergeben.

Hinweis

Alle Antworten unter Matrix mit der höchsten Punktzahl finden ohne Eigenschaft X sind hier gültig, aber nicht optimal. Es gibt T-Matrizen ohne Eigenschaft X, die nicht zyklisch sind.

Zum Beispiel gibt es eine 7 × 12 T-Matrix ohne Eigenschaft X, aber keine solche zyklische Matrix.

21/11 würde alle aktuellen Antworten aus dieser und der vorherigen Herausforderung übertreffen.

Sprachen und Bibliotheken

Sie können jede Sprache verwenden, die einen frei verfügbaren Compiler / Interpreter / etc. für Linux und alle Bibliotheken, die auch für Linux frei verfügbar sind.

Bonus Die erste Antwort mit einer Punktzahl von mehr als 2 erhält sofort eine Prämie von 200 Punkten . Ton Hospel hat dies jetzt erreicht!


Aktuelle Rangliste

  • C ++ . Partitur 31/15 von Ton Hospel
  • Java . Ergebnis 36/19 von Peter Taylor
  • Haskell . Ergebnis 14/8 von alexander-brett
Gemeinschaft
quelle
Mit "zwei nicht leeren Spaltengruppen mit nicht identischen Indizes" meinen Sie zwei Spaltengruppen, die nicht zusammenhängend sind? Oder, um dies neu zu formulieren, sind {1, 3}, {1, 5} zwei gültige Teilmengen von Spalten?
pawel.boczarski
@ pawel.boczarski Nein, nicht disjunkt. Einfach nicht identisch. Also ist {1, 3}, {1, 5} gültig.
In Ordnung. Was ist mit M [i, 1] - ist es ein "Ausleihen" aus der letzten Spalte von M [i-1] (Null ist kein gültiger Matrixspaltenindex)? Und tatsächlich ist dies "oben und links" und nicht "oben und rechts".
pawel.boczarski
@ pawel.boczarski "richtig" war ein Tippfehler. Vielen Dank. Die erste Zeile und Spalte kann beliebig eingestellt werden. Sie definieren den gesamten Rest der Matrix. Beantwortet das deine Frage?
OK ich habe es. Es war meine Schuld, nicht sorgfältig gelesen zu haben, dass auch die erste Spalte definiert ist.
pawel.boczarski

Antworten:

6

C ++, Partitur 23/12 25/13 27/14 28/14 31/15

Endlich ein Ergebnis mit Verhältnis> 2:

rows=15,cols=31
1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 1 1 0 
1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 1 1 
1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 1 
1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 
1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 
0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 
0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 
1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 
0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 
0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 
0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 
1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 
0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 
0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 
1 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 

Ich habe 1 bis 14 Zeilen vollständig erkundet. 15 würde zu lange dauern, um vollständig zu erkunden. Die Ergebnisse sind:

1/1   = 1
2/2   = 1
4/3   = 1.333
5/4   = 1.25
7/5   = 1.4
9/6   = 1.5
12/7  = 1.714
14/8  = 1.75
16/9  = 1.778
18/10 = 1.8
20/11 = 1.818
23/12 = 1.917
25/13 = 1.923
28/14 = 2

Der unten angegebene Code ist eine ältere Version des Programms. Die neueste Version finden Sie unter https://github.com/thospel/personal-propertyX .

/*
  Compile using something like:
    g++ -Wall -O3 -march=native -fstrict-aliasing -std=c++11 -g propertyX.cpp -lpthread -o propertyX
*/
#include <cstdint>
#include <climits>
#include <ctgmath>
#include <iostream>
#include <vector>
#include <array>
#include <chrono>
#include <mutex>
#include <atomic>
#include <thread>

using namespace std;

const int ELEMENTS = 2;

using uint    = unsigned int;
using Element = uint64_t;
using Column  = array<Element, ELEMENTS>;
using Set     = vector<Column>;
using Sum     = uint8_t;
using Index   = uint32_t;
using sec = chrono::seconds;

int const PERIOD = 5*60;
int const MAX_ROWS = 54;
int const COL_FACTOR = (MAX_ROWS+1) | 1;                // 55
int const ROW_ZERO   = COL_FACTOR/2;                    // 27
int const ROWS_PER_ELEMENT = CHAR_BIT * sizeof(Element) / log2(COL_FACTOR); //11
Element constexpr ELEMENT_FILL(Element v = ROW_ZERO, int n = ROWS_PER_ELEMENT) {
    return n ? ELEMENT_FILL(v, n-1) * COL_FACTOR + v : 0;
}
Element constexpr POWN(Element v, int n) {
    return n ? POWN(v, n-1)*v : 1;
}
Element const ELEMENT_TOP = POWN(COL_FACTOR, ROWS_PER_ELEMENT -1);
int const MAX_COLS = ROWS_PER_ELEMENT * ELEMENTS;       // 22

atomic<Index> col_next;
atomic<uint>  period;
chrono::steady_clock::time_point start;
mutex period_mutex;

uint ratio_row;
uint ratio_col;
mutex ratio_mutex;

auto const nr_threads = thread::hardware_concurrency();
// auto const nr_threads = 1;

struct State {
    State(uint cols);
    void process(Index i);
    void extend(uint row);
    void print(uint rows);
    Index nr_columns() const { return static_cast<Index>(1) << cols_; }

    Column last_;
    Element top_;
    int top_offset_;
    uint ratio_row_ = 0;
    uint ratio_col_ = 1;
    uint cols_;
    array<Sum, MAX_ROWS + MAX_COLS -1> side;
    vector<Set> sets;
};

ostream& operator<<(ostream& os, Column const& column) {
    for (int i=0; i<ELEMENTS; ++i) {
        auto v = column[i];
        for (int j=0; j<ROWS_PER_ELEMENT; ++j) {
            auto bit = v / ELEMENT_TOP;
            cout << " " << bit;
            v -= bit * ELEMENT_TOP;
            v *= COL_FACTOR;
        }
    }
    return os;
}

State::State(uint cols) : cols_{cols} {
    sets.resize(MAX_ROWS+2);
    for (int i=0; i<2; ++i) {
        sets[i].resize(2);
        for (int j=0; j < ELEMENTS; ++j) {
            sets[i][0][j] =  ELEMENT_FILL();
            sets[i][1][j] =  static_cast<Element>(-1) - ELEMENT_FILL(1);
        }
    }
    top_ = POWN(COL_FACTOR, (cols_-1) % ROWS_PER_ELEMENT);
    top_offset_ = ELEMENTS - 1 - (cols_-1) / ROWS_PER_ELEMENT;
}

void State::print(uint rows) {
    for (auto c=0U; c<cols_;c++) {
        for (auto r=0U; r<rows;r++) {
            cout << static_cast<int>(side[cols_-c+r-1]) << " ";
        }
        cout << "\n";
    }
    cout << "----------" << endl;
}

void check(uint cols, uint t) {
    State state(cols);

    Index nr_columns = state.nr_columns();
    while (1) {
        Index col = col_next++;
        if (col >= nr_columns) break;
        state.process(col);

        auto now = chrono::steady_clock::now();
        auto elapsed = chrono::duration_cast<sec>(now-start).count();
        if (elapsed >= period) {
            lock_guard<mutex> lock{period_mutex};
            if (elapsed >= period) {
                cout << "col=" << col << "/" << nr_columns << " (" << 100.*col/nr_columns << "% " << elapsed << " s)" << endl;
                period = (elapsed/PERIOD+1)*PERIOD;
            }
        }
    }
}

void State::process(Index col) {
    last_.fill(0);
    for (uint i=0; i<cols_; ++i) {
        Element bit = col >> i & 1;
        side[i] = bit;
        Element carry = 0;
        for (int j=0; j<ELEMENTS; ++j) {
            auto c = last_[j] % COL_FACTOR;
            last_[j] = last_[j] / COL_FACTOR + carry * ELEMENT_TOP;
            if (j == top_offset_ && bit) last_[j] += top_;
            carry = c;
        }
    }
    // cout << "col=" << col << ", value=" << last_ << "\n";
    extend(0);
}

void State::extend(uint row) {
    // cout << "Extend row " << row << " " << static_cast<int>(side[cols_+row-1]) << "\n";
    if (row >= MAX_ROWS) throw(range_error("row out of range"));

    // Execute subset sum. The new column is added to set {from} giving {to}
    // {sum} is the other set.
    auto const& set_from = sets[row];
    auto const& set_sum  = sets[row + 1];
    auto      & set_to   = sets[row + 2];
    if (set_to.size() == 0) {
        auto size = 3 * set_from.size() - 2;
        set_to.resize(size);
        for (int j=0; j<ELEMENTS; ++j)
            set_to[size-1][j] = static_cast<Element>(-1) - ELEMENT_FILL(1);
    }

    // Merge sort {set_from - last_} , {set_from} and {set_from + last_}
    auto ptr_sum    = &set_sum[1][0];
    auto ptr_low    = &set_from[0][0];
    auto ptr_middle = &set_from[0][0];
    auto ptr_high   = &set_from[0][0];
    Column col_low, col_high;
    for (int j=0; j<ELEMENTS; ++j) {
        col_low   [j] = *ptr_low++  - last_[j];
        col_high  [j] = *ptr_high++ + last_[j];
    }

    auto ptr_end = &set_to[set_to.size()-1][0];
    auto ptr_to  = &set_to[0][0];
    while (ptr_to < ptr_end) {
        for (int j=0; j<ELEMENTS; ++j) {
            if (col_low[j] < ptr_middle[j]) goto LOW;
            if (col_low[j] > ptr_middle[j]) goto MIDDLE;
        }
        // low == middle
        // cout << "low == middle\n";
        return;

      LOW:
        // cout << "LOW\n";
        for (int j=0; j<ELEMENTS; ++j) {
            if (col_low[j] < col_high[j]) goto LOW0;
            if (col_low[j] > col_high[j]) goto HIGH0;
        }
        // low == high
        // cout << "low == high\n";
        return;

      MIDDLE:
        // cout << "MIDDLE\n";
        for (int j=0; j<ELEMENTS; ++j) {
            if (ptr_middle[j] < col_high[j]) goto MIDDLE0;
            if (ptr_middle[j] > col_high[j]) goto HIGH0;
        }
        // middle == high
        // cout << "middle == high\n";
        return;

      LOW0:
        // cout << "LOW0\n";
        for (int j=0; j<ELEMENTS; ++j) {
            *ptr_to++  = col_low[j];
            col_low[j] = *ptr_low++ - last_[j];
        }
        goto SUM;

      MIDDLE0:
        // cout << "MIDDLE0\n";
        for (int j=0; j<ELEMENTS; ++j)
            *ptr_to++ = *ptr_middle++;
        goto SUM;

      HIGH0:
        // cout << "HIGH0\n";
        for (int j=0; j<ELEMENTS; ++j) {
            *ptr_to++ = col_high[j];
            col_high[j] = *ptr_high++ + last_[j];
        }
        goto SUM;
      SUM:
        for (int j=-ELEMENTS; j<0; ++j) {
            if (ptr_to[j] > ptr_sum[j]) {
                ptr_sum += ELEMENTS;
                goto SUM;
            }
            if (ptr_to[j] < ptr_sum[j]) goto DONE;
        }
        // sum == to
        for (int j=-ELEMENTS; j<0; ++j)
            if (ptr_to[j] != ELEMENT_FILL()) {
                // sum == to and to != 0
                // cout << "sum == to\n";
                // cout << set_sum[(ptr_sum - &set_sum[0][0])/ELEMENTS-1] << "\n";
                return;
            }
      DONE:;
    }
    // cout << "Wee\n";
    auto row1 = row+1;
    if (0)
        for (uint i=0; i<row1+2; ++i) {
            cout << "Set " << i << "\n";
            auto& set = sets[i];
            for (auto& column: set)
                cout << column << "\n";
        }

    if (row1 * ratio_col_ > ratio_row_ * cols_) {
        ratio_row_ = row1;
        ratio_col_ = cols_;
        lock_guard<mutex> lock{ratio_mutex};

        if (ratio_row_ * ratio_col > ratio_row * ratio_col_) {

            auto now = chrono::steady_clock::now();
            auto elapsed = chrono::duration_cast<sec>(now-start).count();
            cout << "cols=" << cols_ << ",rows=" << row1 << " (" << elapsed << " s)\n";
            print(row1);
            ratio_row = ratio_row_;
            ratio_col = ratio_col_;
        }
    }

    auto last = last_;

    Element carry = 0;
    for (int j=0; j<ELEMENTS; ++j) {
        auto c = last_[j] % COL_FACTOR;
        last_[j] = last_[j] / COL_FACTOR + carry * ELEMENT_TOP;
        carry = c;
    }

    side[cols_+row] = 0;
    extend(row1);

    last_[top_offset_] += top_;
    side[cols_+row] = 1;
    extend(row1);

    last_ = last;
}

void my_main(int argc, char** argv) {
    if (!col_next.is_lock_free()) cout << "col_next is not lock free\n";
    if (!period.  is_lock_free()) cout << "period is not lock free\n";

    int min_col = 2;
    int max_col = MAX_COLS;
    if (argc > 1) {
        min_col = atoi(argv[1]);
        if (min_col < 2)
            throw(range_error("Column must be >= 2"));
        if (min_col > MAX_COLS)
            throw(range_error("Column must be <= " + to_string(MAX_COLS)));
    }
    if (argc > 2) {
        max_col = atoi(argv[2]);
        if (max_col < min_col)
            throw(range_error("Column must be >= " + to_string(min_col)));
        if (max_col > MAX_COLS)
            throw(range_error("Column must be <= " + to_string(MAX_COLS)));
    }

    for (int cols = min_col; cols <= max_col; ++cols) {
        cout << "Trying " << cols << " columns" << endl;
        ratio_row = 0;
        ratio_col = 1;
        col_next = 0;
        period = PERIOD;
        start = chrono::steady_clock::now();
        vector<thread> threads;
        for (auto t = 1U; t < nr_threads; t++)
            threads.emplace_back(check, cols, t);
        check(cols, 0);
        for (auto& thread: threads)
            thread.join();
    }
}

int main(int argc, char** argv) {
    try {
        my_main(argc, argv);
    } catch(exception& e) {
        cerr << "Error: " << e.what() << endl;
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}
Ton Hospel
quelle
Das ist toll. Das große Rätsel ist, ob Sie jemals eine Punktzahl von 2 bekommen können.
Nach Extrapolation sollte es 28/14 geben, was meiner Meinung nach wirklich aufregend wäre. Aber ist es nur unerreichbar?
n = 14 würde mit meinem aktuellen Code auf meiner 8-Kern-CPU ungefähr 200 Tage dauern. Der Code kann wahrscheinlich um 30% oder so beschleunigt werden. Danach gehen mir die Ideen aus. Und Ihre Hochrechnung scheint sowieso ziemlich optimistisch ...
Ton Hospel
Ich denke, die zirkulierende 50 x 25-Matrix mit der ersten Zeile 01011011100010111101000001100111110011010100011010 könnte funktionieren. Dies wurde durch eine Optimierungsheuristik festgestellt, die nützlich sein könnte.
140 Stunden für eine erschöpfende Abdeckung von n = 14 sind sehr beeindruckend schnell, muss ich sagen.
2

Haskell 14/8 = 1,75

1 1 0 0 0 1 0 1 1 0 1 1 0 0
1 1 1 0 0 0 1 0 1 1 0 1 1 0
0 1 1 1 0 0 0 1 0 1 1 0 1 1
1 0 1 1 1 0 0 0 1 0 1 1 0 1
0 1 0 1 1 1 0 0 0 1 0 1 1 0
0 0 1 0 1 1 1 0 0 0 1 0 1 1
0 0 0 1 0 1 1 1 0 0 0 1 0 1
0 0 0 0 1 0 1 1 1 0 0 0 1 0

Zuvor 9/6 = 1,5

1 0 1 0 1 1 0 0 1
1 1 0 1 0 1 1 0 0
1 1 1 0 1 0 1 1 0
1 1 1 1 0 1 0 1 1
1 1 1 1 1 0 1 0 1
1 1 1 1 1 1 0 1 0

Ich schrieb dies, sah mir dann die Antworten auf die andere Frage an und war ... entmutigt.

import Data.List
import Data.Hashable
import Control.Monad
import Control.Parallel.Strategies
import Control.Parallel
import qualified Data.HashSet as S

matrix§indices = [ matrix!!i | i<-indices ]

powerset :: [a] -> [[a]]
powerset = filterM (const [True, False])

hashNub :: (Hashable a, Eq a) => [a] -> [a]
hashNub l = go S.empty l
    where
      go _ []     = []
      go s (x:xs) = if x `S.member` s
        then go s xs
        else x : go (S.insert x s) xs

getMatrix :: Int -> Int -> [Int] -> [[Int]]
getMatrix width height vector = [ vector § [x..x+width-1] | x<-[0..height-1] ]

hasDuplicate :: (Hashable a, Eq a) => [a] -> Bool
hasDuplicate m = go S.empty m
    where
        go _ [] = False
        go s (x:xs) = if x `S.member` s
            then True
            else go (S.insert x s) xs

hasProperty :: [[Int]] -> Bool
hasProperty matrix =
    let
        base = replicate (length (matrix !! 0)) 0::[Int]
    in
        if elem base matrix then
            False
        else
            if hasDuplicate matrix then
                False
            else
                if hasDuplicate (map (foldl (zipWith (+)) base) (powerset matrix)) then
                    False
                else
                    True


pmap = parMap rseq

matricesWithProperty :: Int -> Int -> [[[Int]]]
matricesWithProperty n m =
    let
        base = replicate n 0::[Int]
    in
    filter (hasProperty) $
    map (getMatrix n m) $
    sequence [ [0,1] | x<-[0..n+m-1] ]

firstMatrixWithProperty :: Int -> Int -> [[Int]]
firstMatrixWithProperty n m = head $ matricesWithProperty n m

main = mapM (putStrLn. show) $ map (firstMatrixWithProperty 8) [1..]
alexander-brett
quelle
Vielen Dank! Eine Haskell-Antwort ist immer sehr willkommen. Ich denke, der erste interessante Fall ist 12/7. Kannst du das bekommen?
Ich habe es auf einem Dual-Core-Laptop von 2009 ausgeführt, also nein :) Ich werde es jedoch erneut auf einem schnelleren Computer versuchen
Alexander-Brett
Sehr schön. Ich habe gerade einen Kommentar hinzugefügt, dass 21/11 alle vorherigen Antworten übertreffen würde.
Können Sie bitte genau erklären, was Ihr Code ausgibt?
In mainist die Zahl (in diesem Fall 8) die Höhe der Matrix, und das Programm durchläuft die Breiten [1..]. Für jede Kombination aus Höhe und Breite wird ein Array von Spalten einer gültigen Matrix gedruckt.
Alexander-Brett
1

C.

Hier ist eine Antwort, die funktioniert und wesentlich speichereffizienter ist als der Haskell. Leider ist mein Computer immer noch zu langsam, um in angemessener Zeit eine bessere Leistung als 14/8 zu erzielen.

Versuchen Sie, gcc -std=c99 -O2 -fopenmp -o matrices.exe matrices.cmit matrices.exe width heightoder ähnlich zu kompilieren und auszuführen . Die Ausgabe ist eine Ganzzahl, deren Bits die Basis für die betreffende Matrix bilden, zum Beispiel:

$ matrices.exe 8 14
...
valid i: 1650223

Dann ist da 1650223 = 0b110010010111000101111die fragliche Matrix:

0 0 1 1 1 0 1 0 0 1 0 0 1 1
0 ...
1 ...
0
1
1
1
1

Wenn jemand mit 8 Kernen und Zeit auf seinen Händen dies für eine Weile ausführen möchte, denke ich, dass einige gute Dinge resultieren könnten :)


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/*
 * BEGIN WIKIPEDIA CODE
 */
const long long m1  = 0x5555555555555555; //binary: 0101...
const long long m2  = 0x3333333333333333; //binary: 00110011..
const long long m4  = 0x0f0f0f0f0f0f0f0f; //binary:  4 zeros,  4 ones ...
const long long m8  = 0x00ff00ff00ff00ff; //binary:  8 zeros,  8 ones ...
const long long m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ...
const long long m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones
const long long hff = 0xffffffffffffffff; //binary: all ones
const long long h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...
//This uses fewer arithmetic operations than any other known
//implementation on machines with fast multiplication.
//It uses 12 arithmetic operations, one of which is a multiply.
long long hamming(long long x) {
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits
    return (x * h01)>>56;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
/*
 * END WIKIPEDIA CODE
 */

int main ( int argc, char *argv[] ) {
    int height;
    int width;

    sscanf(argv[1], "%d", &height);
    sscanf(argv[2], "%d", &width);

    #pragma omp parallel for
    for (
        /*
         * We know that there are 2^(h+w-1) T-matrices, defined by the entries
         * in the first row and first column. We'll let the long long i
         * represent these entries, with 1s represented by set bits.
         *
         * The first (0) and last (1) matrix we will ignore.
         */
        long long i = 1;
        i < (1 << (height+width-1))-1;
        i++
    ) {
        // Flag for keeping track as we go along.
        int isvalid = 1;

        /*
         * Start by representing the matrix as an array of columns, with each
         * non-zero matrix entry as a bit. This allows us to construct them and
         * check equality very quickly.
         */
        long *cols = malloc(sizeof(long)*width);
        long colmask = (1 << height)-1;
        for (int j = 0; j < width; j++) {
            cols[j] = (i >> j) & colmask;
            if (cols[j] == 0) {
                //check no zero rows
                isvalid = 0;
            } else {
                //check no duplicate rows
                for (int k = 0; k < j; k++) {
                    if (cols[j] == cols[k]) {
                        isvalid = 0;
                    }
                }
            }
        }

        if (isvalid == 1) {
            /*
             * We'll also represent the matrix as an array of rows, in a
             * similar manner.
             */
            long *rows = malloc(sizeof(long)*height);
            long rowmask = (1 << width)-1;
            for (int j = 0; j < height; j++) {
                rows[j] = (i >> j) & rowmask;
            }

            int *sums[(1 << width)];
            for (long j = 0; j < 1<<width; j++) {
                sums[j] = (int*)malloc(sizeof(int)*height);
            }

            for (
                /*
                 * The powerset of columns has size 2^width. Again with the
                 * long; this time each bit represents whether the
                 * corresponding row is a member of the subset. The nice thing
                 * about this is we can xor the permutation with each row,
                 * then take the hamming number of the resulting number to get
                 * the sum.
                 */
                long permutation = 1;
                (isvalid == 1) && (permutation < (1 << width)-1);
                permutation ++
            ) {
                for (int j = 0; j < height; j++) {
                    sums[permutation][j] = hamming( rows[j] & permutation);
                }
                for (int j = permutation-1; (isvalid == 1) && (j > -1); j--) {
                    if (memcmp(sums[j], sums[permutation], sizeof(int)*height) == 0) {
                        isvalid = 0;
                    }
                }
            }

            for (long j = 0; j < 1<<width; j++) {
                free(sums[j]);
            }

            free(rows);

        }

        if (isvalid == 1) {
            printf ("valid i: %ld\n", i);
        }

        free(cols);
    }

    return 0;
}
alexander-brett
quelle
Ich bekomme alexander-brett.c: In der Funktion 'main': alexander-brett.c: 107: 21: Warnung: implizite Deklaration der Funktion 'memcmp' [-Wimplicit-Funktionsdeklaration] if (memcmp (sums [j], Summen [Permutation], Größe von (int) * Höhe) == 0) {^ alexander-brett.c: 122: 13: Warnung: Format '% ld' erwartet Argument vom Typ 'long int', aber Argument 2 hat Typ ' long long int '[-Wformat =] printf ("gültig i:% ld \ n", i);
Wie lange dauert ./alexander-brett 8 14 für Sie?
Hallo Lembik, 8 14 hat auf einer Quad-Core-Maschine in einer Stunde 5 Antworten für mich erhalten. Ich habe es geschafft, mit diesen Headern unter Windows zu kompilieren. Es wäre seltsam, wenn memcmp verloren gehen würde ...
alexander-brett
Ich habe Ihren Code mit 7 12 ausprobiert und eine der Antworten, die er ausgibt, ist valid i: 7481. In Python bin (7481) ist 0b1110100111001, was nicht lang genug ist. Irgendeine Idee, was los ist?