Dua baris matriks adalah ortogonal jika produk dalamnya sama dengan nol. Panggil sebuah matriks dengan semua baris ortogonal berpasangan, sebuah matriks ortogonal . Sebuah matriks circulant adalah salah satu di mana setiap vektor baris diputar satu elemen ke relatif kanan ke vektor baris sebelumnya. Kami hanya akan tertarik pada matriks di mana entri adalah salah satu -1
atau 1
.
Tugas
Tulis kode untuk menghitung sebanyak mungkin perbedaan n/2
dengan n
matriks ortogonal, edaran mungkin dalam 2 menit (untuk genap n
).
Memasukkan
Kode tidak memiliki input. Itu dapat mencoba nilai rata apa pun yang n
disukainya. Misalnya, kode dapat mencoba semua n
yang berlipat 4
mulai dari yang terkecil dan juga coba n = 2
.
Keluaran
Jumlah matriks sirkuler ortogonal yang Anda temukan. Seharusnya juga ada saklar sederhana dalam kode Anda untuk memungkinkannya mengeluarkan matriks sendiri.
Skor
Jumlah matriks sirkuler yang Anda temukan.
Petunjuk
Matriks orthogonal n/2
oleh n
sirkulant hanya ada ketika n
kelipatan 4
atau n
kurang dari 4
.
Contoh matriks circulant ortogonal adalah:
-1 1 -1 -1
-1 -1 1 -1
Kiat untuk pendekatan naif
Pendekatan yang paling naif adalah hanya mengulangi semua matriks yang mungkin. Ini dapat dipercepat dengan menggunakan dua pengamatan berikut.
Untuk menguji ortogonalitas dari matriks sirkuler, kita hanya perlu membandingkan setiap baris dengan yang pertama. Ini diimplementasikan dalam kode sampel.
Kita dapat mengulangi kata - kata Lyndon dan kemudian jika kita menemukan matriks ortogonal dikalikan dengan jumlah rotasi yang mungkin. Ini adalah ide yang belum diuji sehingga mungkin bermasalah.
Kode sampel
Ini adalah jawaban python yang sangat sederhana dan naif. Saya menjalankannya menggunakan timeout 120
.
import itertools
def check_orthogonal(row):
for i in xrange(1,int(n/2)):
if (sum(row[j]*row[(j+i) % n] for j in xrange(n)) != 0):
return False
return True
counter = 0
for n in xrange(4,33,4):
for row in itertools.product([-1,1],repeat = n):
if check_orthogonal(row):
counter +=1
print "Counter is ", counter, ". n = ", n
Tes kebenaran
Sebab n = 4,8,12,16,20,24,28
, jumlah matriks berbeda yang harus Anda dapatkan adalah 12,40,144,128,80,192,560
, masing-masing.
Tingkat kedahsyatan
Menilai dengan kode sampel, saya dengan ini menyajikan dua tingkat kedahsyatan yang dapat dicoba dicapai oleh jawaban apa pun.
Kedahsyatan level perak dicapai dengan mendapatkan skor atau 1156 .
Tingkat keangkeran emas adalah untuk mendapatkan yang lebih tinggi dari itu.
Bahasa dan perpustakaan
Anda dapat menggunakan bahasa atau perpustakaan apa pun yang Anda suka (yang tidak dirancang untuk tantangan ini). Namun, untuk tujuan penilaian saya akan menjalankan kode Anda di mesin saya jadi tolong berikan instruksi yang jelas untuk bagaimana menjalankannya di Ubuntu.
Mesin Saya Pengaturan waktu akan dijalankan pada mesin saya. Ini adalah instalasi standar Ubuntu pada Prosesor Delapan-Core AMD 8GB 8GB AMD. Ini juga berarti saya harus dapat menjalankan kode Anda.
Memimpin jawaban
332 oleh flawr di Octave
404 oleh RT dalam Python
744 oleh Contoh Solusi menggunakan pypy
1156 oleh Thomas Kwa menggunakan Java . Kedahsyatan tingkat perak!
1588 oleh Reimer Behrends di OCaml . Kedahsyatan tingkat emas!
n
yang merupakan kelipatan empat?Jawaban:
OCaml, 1588 (n = 36)
Solusi ini menggunakan pendekatan pola bit biasa untuk mewakili vektor -1s dan 1s. Produk skalar seperti biasa dihitung dengan mengambil xor dari vektor dua bit dan mengurangi n / 2. Vektor bersifat ortogonal jika xornya memiliki n / 2 bit yang tepat.
Kata-kata Lyndon sendiri tidak berguna sebagai representasi yang dinormalisasi untuk ini, karena mereka mengecualikan pola apa pun yang merupakan rotasi itu sendiri. Mereka juga relatif mahal untuk dihitung. Oleh karena itu, kode ini menggunakan bentuk normal yang agak sederhana, yang mensyaratkan bahwa urutan nol terpanjang berturut-turut setelah rotasi (atau salah satunya, jika ada kelipatannya) harus menempati bit paling signifikan. Oleh karena itu, bit yang paling tidak signifikan selalu 1.
Perhatikan juga bahwa setiap vektor kandidat harus memiliki setidaknya n / 4 (dan paling banyak 3n / 4). Karena itu, kami hanya mempertimbangkan vektor dengan n / 4 ... n / 2 bit yang ditetapkan, karena kami dapat menurunkan yang lain melalui komplemen dan rotasi (dalam praktiknya, semua vektor tersebut tampaknya memiliki antara n / 2-2 dan n / 2 + 2 yang , tapi itu sepertinya juga sulit dibuktikan).
Kami membangun formulir normal ini dari bit yang paling signifikan, mengamati kendala bahwa setiap sisa nol yang berjalan (disebut "celah" dalam kode) harus mengikuti persyaratan bentuk normal kami. Secara khusus, selama setidaknya satu bit lagi harus ditempatkan, harus ada ruang untuk celah saat ini dan yang lain selain itu setidaknya sebesar celah saat ini atau celah lain yang diamati sejauh ini.
Kami juga mengamati bahwa daftar hasilnya kecil. Oleh karena itu, kami tidak mencoba untuk menghindari duplikat selama proses penemuan, tetapi hanya mencatat hasil dalam set per-pekerja dan menghitung penyatuan set ini di akhir.
Perlu dicatat bahwa biaya runtime algoritma masih tumbuh secara eksponensial dan pada tingkat yang sebanding dengan versi brute-force; apa ini membeli kita pada dasarnya adalah pengurangan oleh faktor konstan, dan datang pada biaya suatu algoritma yang lebih sulit untuk disejajarkan daripada versi brute-force.
Output untuk n hingga 40:
Program ini ditulis dalam OCaml, untuk dikompilasi dengan:
Jalankan
./orthcirc -help
untuk melihat opsi apa yang didukung oleh program.Pada arsitektur yang mendukungnya,
-fno-PIC
mungkin menawarkan sedikit peningkatan kinerja tambahan.Ini ditulis untuk OCaml 4.02.3, tetapi mungkin juga berfungsi dengan versi yang lebih lama (asalkan tidak terlalu lama).
UPDATE: Versi baru ini menawarkan paralelisasi yang lebih baik. Perhatikan bahwa ia menggunakan
p * (n/4 + 1)
utas pekerja per instance masalah, dan beberapa dari mereka masih akan berjalan jauh lebih pendek daripada yang lain. Nilaip
must a power of 2. Speedup pada 4-8 core minimal (mungkin sekitar 10%), tetapi itu menskala lebih baik ke sejumlah besar core untuk besarn
.sumber
Jawa, 1156 matriks
Ini menggunakan bitmasking yang cukup naif, dan membutuhkan waktu di bawah 15 detik untuk n = 28 pada mesin saya.
Matriks Circulant ditentukan oleh baris pertama mereka. Oleh karena itu, saya mewakili baris pertama dari matriks sebagai vektor bit: 1 dan 0 mewakili -1 dan 1. Dua baris adalah ortogonal ketika jumlah bit yang diset ketika mereka dikoreksi bersama adalah n / 2.
Saya tidak bisa membuat Eclipse bekerja sekarang, jadi ini diuji pada repl.it.
Berikut adalah jumlah baris pertama yang ortogonal ke baris pertama setelahnya untuk n = 28:
Optimasi:
long
, dan kemudian menggunakan satuand
dengan bit N yang lebih rendah untuk mengekstrak yang diperlukan.Kemungkinan optimasi lebih lanjut:
00
, dan menggunakan rotasi mereka (dan rotasi NOT) ketika kita menemukan matriks ortogonal. Kita dapat melakukan ini karena0101...01
dan1010...10
tidak mungkin baris pertama, dan semua yang lainnya mengandung a00
atau a11
.sumber
n=36
juga.Python (404 matriks pada i5-5300U)
Terutama memposting ini sebagai titik awal untuk meningkatkan orang lain, ini dapat dibersihkan banyak, diparalelkan, dll.
sumber
Matlab / Oktaf, 381/328 matriks
Juga hanya pendekatan naif, mencoba setiap kombinasi yang mungkin.
sumber
n
danz
, dua ini dapat dikomentari dengan satu%
. Dan kemudian Anda dapat menambahkan;
setelahcounter = counter+1
dank/N
yang akan menekan output.