सबसे तेज अनुमानित आम भाजक


13

अवलोकन

इस चुनौती में, आपको दो नंबर दिए जाएंगे जो कि एक मध्यम आकार के एक नंबर से कई गुना छोटे ऑफसेट हैं। आपको एक मध्यम आकार की संख्या का उत्पादन करना चाहिए जो कि एक छोटे से ऑफसेट को छोड़कर, दोनों संख्याओं का लगभग एक विभाजक है।

शामिल संख्याओं का आकार एक कठिनाई पैरामीटर द्वारा पैरामीटर किया जाएगा l,। आपका उद्देश्य l1 मिनट से कम समय में सबसे बड़ी समस्या को हल करना है ।


सेट अप

दी गई समस्या में, एक गुप्त संख्या pहोगी, जो एक यादृच्छिक l^2( l*l) बिट संख्या होगी। दो गुणक q1, q2होंगे, जो यादृच्छिक l^3बिट संख्या होंगे, और दो ऑफसेट r1, r2होंगे, जो यादृच्छिक lबिट संख्या होंगे।

आपके कार्यक्रम का इनपुट निम्नानुसार होगा x1, x2:

x1 = p * q1 + r1
x2 = p * q2 + r2

यहाँ पायथन में, परीक्षण मामलों को उत्पन्न करने का एक कार्यक्रम है:

from random import randrange
from sys import argv

l = int(argv[1])

def randbits(bits):
    return randrange(2 ** (bits - 1), 2 ** bits)

p = randbits(l ** 2)
print(p)
for i in range(2):
    q_i = randbits(l ** 3)
    r_i = randbits(l)
    print(q_i * p + r_i)

आउटपुट की पहली पंक्ति एक संभावित समाधान है, जबकि दूसरी और तीसरी पंक्ति इनपुट है जिसे आपका प्रोग्राम दिया जाएगा।


आपका कार्यक्रम

दिया x1, x2और l, आपको एक l^2बिट संख्या मिलनी चाहिए p'जो कि x1 % p'और x2 % p'दोनों lबिट संख्याएँ हैं। pहमेशा काम करेंगे, हालांकि अन्य संभावनाएं हो सकती हैं। यहाँ एक समाधान को सत्यापित करने के लिए एक समारोह है:

def is_correct(x1, x2, l, p_prime):
    p_prime_is_good = p_prime >> (l**2 - 1) and not p_prime >> l ** 2
    x1_is_good = (x1 % p_prime) >> (l-1) and not (x1 % p_prime) >> l
    x2_is_good = (x2 % p_prime) >> (l-1) and not (x2 % p_prime) >> l
    return bool(p_prime_is_good and x1_is_good and x2_is_good)

उदाहरण

मान लीजिए l3. जनरेटर प्रोग्राम 9-बिट संख्या के लिए चुनता है p, जो इस मामले में है 442। जनरेटर दो 3बिट संख्या के लिए चुनता है r1, r2, जो हैं 4, 7। जनरेटर दो 27बिट संख्या के लिए चुनता है q1, q2, जो हैं 117964803, 101808039। इन विकल्पों के कारण, x1, x2हैं 52140442930, 44999153245

आपके प्रोग्राम 52140442930, 44999153245को इनपुट के रूप में दिया जाएगा , और 9-बिट नंबर (रेंज में [256, 511]) को आउटपुट करना होगा जैसे कि 52140442930और 44999153245मोडुलो जो नंबर 3 बिट नंबर (रेंज में [4, 7]) देते हैं। 442इस मामले में एकमात्र ऐसा मूल्य है, इसलिए आपके प्रोग्राम को आउटपुट देना होगा 442


और ज्यादा उदाहरण

l = 2
x1 = 1894
x2 = 2060
p = 11
No other p'.

l = 3
x1 = 56007668599
x2 = 30611458895
p = 424
No other p'.

l = 6
x1 = 4365435975875889219149338064474396898067189178953471159903352227492495111071
x2 = 6466809655659049447127736275529851894657569985804963410176865782113074947167
p = 68101195620
I don't know whether there are other p'.

l = 12
x1 = 132503538560485423319724633262218262792296147003813662398252348727558616998821387759658729802732555377599590456096450977511271450086857949046098328487779612488702544062780731169071526325427862701033062986918854245283037892816922645703778218888876645148150396130125974518827547039720412359298502758101864465267219269598121846675000819173555118275197412936184329860639224312426860362491131729109976241526141192634523046343361089218776687819810873911761177080056675776644326080790638190845283447304699879671516831798277084926941086929776037986892223389603958335825223
x2 = 131643270083452525545713630444392174853686642378302602432151533578354175874660202842105881983788182087244225335788180044756143002547651778418104898394856368040582966040636443591550863800820890232349510212502022967044635049530630094703200089437589000344385691841539471759564428710508659169951391360884974854486267690231936418935298696990496810984630182864946252125857984234200409883080311780173125332191068011865349489020080749633049912518609380810021976861585063983190710264511339441915235691015858985314705640801109163008926275586193293353829677264797719957439635
p = 12920503469397123671484716106535636962543473
I don't know whether there are other p'.

l = 12
x1 = 202682323504122627687421150801262260096036559509855209647629958481910539332845439801686105377638207777951377858833355315514789392768449139095245989465034831121409966815913228535487871119596033570221780568122582453813989896850354963963579404589216380209702064994881800638095974725735826187029705991851861437712496046570494304535548139347915753682466465910703584162857986211423274841044480134909827293577782500978784365107166584993093904666548341384683749686200216537120741867400554787359905811760833689989323176213658734291045194879271258061845641982134589988950037
x2 = 181061672413088057213056735163589264228345385049856782741314216892873615377401934633944987733964053303318802550909800629914413353049208324641813340834741135897326747139541660984388998099026320957569795775586586220775707569049815466134899066365036389427046307790466751981020951925232623622327618223732816807936229082125018442471614910956092251885124883253591153056364654734271407552319665257904066307163047533658914884519547950787163679609742158608089946055315496165960274610016198230291033540306847172592039765417365770579502834927831791804602945514484791644440788
p = 21705376375228755718179424140760701489963164

स्कोरिंग

जैसा कि ऊपर उल्लेख किया गया है, आपके कार्यक्रम का स्कोर उच्चतम lहै जो कार्यक्रम 1 मिनट से कम समय में पूरा होता है। अधिक विशेष रूप से, आपका कार्यक्रम 5 यादृच्छिक उदाहरणों के साथ चलाया जाएगा l, और इसे सभी 5 पर एक सही उत्तर का उत्पादन करना होगा, औसत समय 1 मिनट से कम। एक कार्यक्रम का स्कोर उच्चतम होगा lजो उस पर सफल होता है। टाईब्रेकर उस पर औसत समय होगा l

आपको यह अनुमान लगाने के लिए कि किस स्कोर के लिए लक्ष्य करना है, मैंने एक बहुत ही सरल ब्रूट-फोर्स सॉल्वर लिखा। इसे 5 का स्कोर मिला। मैंने एक बहुत बड़ा प्रशंसक लिखा। इसे किस्मत के आधार पर 12 या 13 का स्कोर मिला।


विवरण

उत्तर भर में पूर्ण तुल्यता के लिए, मैं अपने लैपटॉप पर विहित स्कोर देने के लिए समय दूंगा। मैं भी सभी प्रस्तुतियाँ पर एक ही बेतरतीब ढंग से चुने हुए उदाहरण चलाऊंगा, कुछ हद तक भाग्य को कम करने के लिए। मेरे लैपटॉप में 4 सीपीयू, i5-4300U CPU @ 1.9 GHz, 7.5G RAM है।

अपने समय के आधार पर एक अनंतिम स्कोर पोस्ट करने के लिए स्वतंत्र महसूस करें, बस यह स्पष्ट करें कि क्या यह अनंतिम या विहित है।


सबसे तेज कार्यक्रम जीत सकता है!


क्या सन्निकटन निकटतम होना है?
यति

@TuukkaX दोनों संख्याओं के काम का एक कारक होने से कोई भी l^2बिट-संख्या lदूर है। हालांकि आम तौर पर केवल एक ही होता है।
ईसैक

यहाँ कुछ एल्गोरिदम विचारों के साथ एक शोध प्रबंध है: tigerprints.clemson.edu/cgi/… । विशेष रूप से अच्छा और सरल एक खंड 5.1.1 में है
isaacg

I5-4300U 2 कोर (4 धागे), नहीं 4 कोर है।
एंडर्स केसरग

जवाबों:


3

जंग, एल = १३

src/main.rs

extern crate gmp;
extern crate rayon;

use gmp::mpz::Mpz;
use gmp::rand::RandState;
use rayon::prelude::*;
use std::cmp::max;
use std::env;
use std::mem::swap;

// Solver

fn solve(x1: &Mpz, x2: &Mpz, l: usize) -> Option<Mpz> {
    let m = l*l - 1;
    let r = -1i64 << l-2 .. 1 << l-2;
    let (mut x1, mut x2) = (x1 - (3 << l-2), x2 - (3 << l-2));
    let (mut a1, mut a2, mut b1, mut b2) = (Mpz::one(), Mpz::zero(), Mpz::zero(), Mpz::one());
    while !x2.is_zero() &&
        &(max(a1.abs(), b1.abs()) << l-2) < &x1 &&
        &(max(a2.abs(), b2.abs()) << l-2) < &x2
    {
        let q = &x1/&x2;
        swap(&mut x1, &mut x2);
        x2 -= &q*&x1;
        swap(&mut a1, &mut a2);
        a2 -= &q*&a1;
        swap(&mut b1, &mut b2);
        b2 -= &q*&b1;
    }
    r.clone().into_par_iter().map(|u| {
        let (mut y1, mut y2) = (&x1 - &a1*u + (&b1 << l-2), &x2 - &a2*u + (&b2 << l-2));
        for _ in r.clone() {
            let d = Mpz::gcd(&y1, &y2);
            if d.bit_length() >= m {
                let d = d.abs();
                let (mut k, k1) = (&d >> l*l, &d >> l*l-1);
                while k < k1 {
                    k += 1;
                    if (&d%&k).is_zero() {
                        return Some(&d/&k)
                    }
                }
            }
            y1 -= &b1;
            y2 -= &b2;
        }
        None
    }).find_any(|o| o.is_some()).unwrap_or(None)
}

// Test harness

fn randbits(rnd: &mut RandState, bits: usize) -> Mpz {
    rnd.urandom(&(Mpz::one() << bits - 1)) + (Mpz::one() << bits - 1)
}

fn gen(rnd: &mut RandState, l: usize) -> (Mpz, Mpz, Mpz) {
    let p = randbits(rnd, l*l);
    (randbits(rnd, l*l*l)*&p + randbits(rnd, l),
     randbits(rnd, l*l*l)*&p + randbits(rnd, l),
     p)
}

fn is_correct(x1: &Mpz, x2: &Mpz, l: usize, p_prime: &Mpz) -> bool {
    p_prime.bit_length() == l*l &&
        (x1 % p_prime).bit_length() == l &&
        (x2 % p_prime).bit_length() == l
}

fn random_test(l: usize, n: usize) {
    let mut rnd = RandState::new();  // deterministic seed
    for _ in 0..n {
        let (x1, x2, p) = gen(&mut rnd, l);
        println!("x1 = {}", x1);
        println!("x2 = {}", x2);
        println!("l = {}", l);
        println!("p = {}", p);
        println!("x1 % p = {}", &x1 % &p);
        println!("x2 % p = {}", &x2 % &p);
        assert!(is_correct(&x1, &x2, l, &p));
        let p_prime = solve(&x1, &x2, l).expect("no solution found!");
        println!("p' = {}", p_prime);
        assert!(is_correct(&x1, &x2, l, &p_prime));
        println!("correct");
    }
}

// Command line interface

fn main() {
    let args = &env::args().collect::<Vec<_>>();
    if args.len() == 4 && args[1] == "--random" {
        if let (Ok(l), Ok(n)) = (args[2].parse(), args[3].parse()) {
            return random_test(l, n);
        }
    }
    if args.len() == 4 {
        if let (Ok(x1), Ok(x2), Ok(l)) = (args[1].parse(), args[2].parse(), args[3].parse()) {
            match solve(&x1, &x2, l) {
                None => println!("no solution found"),
                Some(p_prime) => println!("{}", p_prime),
            }
            return;
        }
    }
    println!("Usage:");
    println!("    {} --random L N", args[0]);
    println!("    {} X1 X2 L", args[0]);
}

Cargo.toml

[package]
name = "agcd"
version = "0.1.0"
authors = ["Anders Kaseorg <andersk@mit.edu>"]

[dependencies]
rayon = "0.7.1"
rust-gmp = "0.5.0"

चलाने के लिए

cargo build --release
target/release/agcd 56007668599 30611458895 3
target/release/agcd --random 13 5

आधिकारिक परिणाम l = 13 है, औसत समय 41.53 के साथ। l = 14 ने औसतन 2 मी से थोड़ा अधिक समय लिया।
ईसैक

2

गणितज्ञ, एल = ५

यहाँ एक त्वरित 5 समाधान है

(l = #3;
a = #1 - Range[2^(l - 1), 2^l];
b = #2 - Range[2^(l - 1), 2^l];
Last@Intersection[
Flatten[Table[Select[Divisors@a[[i]], # < 2^l^2 &], {i, Length@a}],
 1],
Flatten[Table[Select[Divisors@b[[i]], # < 2^l^2 &], {i, Length@b}],
 1]]
) &

इनपुट
[X1, x2, L]

आदेश में कि कोई भी इसका परीक्षण कर सकता है, यहां प्रमुख जनरेटर है

l = 5;
a = RandomInteger[{2^(l^2 - 1), 2^(l^2)}]
b = RandomInteger[{2^(l^3 - 1), 2^(l^3)}];
c = RandomInteger[{2^(l - 1), 2^l - 1}];
f = RandomInteger[{2^(l^3 - 1), 2^(l^3)}];
g = RandomInteger[{2^(l - 1), 2^l - 1}];
x = a*b + c
y = a*f + g

L मान रन चुनें, कोड और आपको तीन नंबर मिलेंगे।
अंतिम दो को एल के साथ इनपुट के रूप में रखें, और आपको पहला मिलना चाहिए


मैंने इस समाधान को l = 5 के स्कोर के रूप में सत्यापित किया है। टाईमब्रेकर के रूप में समय की जरूरत है तो मैं इसे करूंगा।
ईसैक

1

गणितज्ञ, एल = १२

ClearAll[l, a, b, k, m];
(l = #3;
a = #1 - Range[2^(l - 1), 2^l];
b = #2 - Range[2^(l - 1), 2^l];
k = Length@a;
m = Length@b;
For[i = 1, i <= k, i++, 
For[j = 1, j <= m, j++, If[2^(l^2 - 1) < GCD[a[[i]], b[[j]]],
 If[GCD[a[[i]], b[[j]]] > 2^l^2, 
  Print@Max@
    Select[Divisors[GCD[a[[i]], b[[j]]]], 
     2^(l^2 - 1) < # < 2^l^2 &]; Abort[], 
  Print[GCD[a[[i]], b[[j]]]];
  Abort[]]]]]) &

इनपुट [X1, x2, L]

आदेश में कि कोई भी इसका परीक्षण कर सकता है, यहां प्रमुख जनरेटर है

l = 12;
a = RandomInteger[{2^(l^2 - 1), 2^(l^2)}]
b = RandomInteger[{2^(l^3 - 1), 2^(l^3)}];
c = RandomInteger[{2^(l - 1), 2^l - 1}];
f = RandomInteger[{2^(l^3 - 1), 2^(l^3)}];
g = RandomInteger[{2^(l - 1), 2^l - 1}];
x = a*b + c
y = a*f + g

L मान चुनें, कोड चलाएं और आपको तीन नंबर मिलेंगे।
अंतिम दो को एल के साथ इनपुट के रूप में रखें, और आपको पहला मिलना चाहिए


जब मैंने इसके साथ परीक्षण किया l = 12, तो इसने गलत परिणाम दिया। विशेष रूप से, परिणामी भाजक एक 146-बिट संख्या थी, जो बहुत बड़ी है। मुझे लगता है कि आपको इसे ठीक करने के लिए केवल एक छोटे से बदलाव की आवश्यकता होगी।
इसहाक

मैंने उपर्युक्त अंतिम उदाहरण के रूप में असफल मामले को जोड़ा। आपके सॉल्वर ने 3 * p के बराबर जवाब दिया, जो थोड़ा बहुत बड़ा था। आपके कोड को देखते हुए, ऐसा लगता है कि आप केवल यह जांचते हैं कि आपके आउटपुट में कम से कम l^2बिट्स हैं, लेकिन आपको यह भी जांचने की आवश्यकता है कि इसमें अधिकांश l^2बिट्स हैं।
इसहाक

उसी परीक्षण मामले पर जो पहले विफल हो गया था, अब भी काम नहीं कर रहा है। मैं मैथेमेटिका से सुपर परिचित नहीं हूं, लेकिन यह ऐसा लग रहा था जैसे कोई आउटपुट नहीं है। मुझे लगता है कि समस्या यह है कि यह एक ऐसा कारक ढूंढ रहा है जो बहुत बड़ा है, और फिर वांछित सीमा में कारक का विभाजक खोजने के बजाय, यह सिर्फ इसे छोड़ रहा है।
इसहाक


आधिकारिक स्कोर L = 12 है, जिसमें 52.7 का औसत समय है। बहुत बढ़िया!
इसहाक

1

पायथन, एल = 15, औसत समय 39.9 एस

from sys import argv
from random import seed, randrange

from gmpy2 import gcd, mpz
import gmpy2

def mult_buckets(buckets):
    if len(buckets) == 1:
        return buckets[0]
    new_buckets = []
    for i in range(0, len(buckets), 2):
        if i == len(buckets) - 1:
            new_buckets.append(buckets[i])
        else:
            new_buckets.append(buckets[i] * buckets[i+1])
    return mult_buckets(new_buckets)


def get_products(xs, l):
    num_buckets = 1000
    lower_r = 1 << l - 1
    upper_r = 1 << l
    products = []
    bucket_size = (upper_r - lower_r)//num_buckets + 1
    for x in xs:
        buckets = []
        for bucket_num in range(num_buckets):
            product = mpz(1)
            for r in range(lower_r + bucket_num * bucket_size,
                           min(upper_r, lower_r + (bucket_num + 1) * bucket_size)):
                product *= x - mpz(r)
            buckets.append(product)
        products.append(mult_buckets(buckets))
    return products

def solve(xs, l):
    lower_r = 2**(l - 1)
    upper_r = 2**l
    lower_p = 2**(l**2 - 1)
    upper_p = 2**(l**2)

    products = get_products(xs, l)
    overlap = gcd(*products)
    candidate_lists = []
    for x in xs:
        candidates = []
        candidate_lists.append(candidates)
        for r in range(lower_r, upper_r):
            common_divisor = gcd(x-r, overlap)
            if common_divisor >= lower_p:
                candidates.append(common_divisor)
    to_reduce = []
    for l_candidate in candidate_lists[0]:
        for r_candidate in candidate_lists[1]:
            best_divisor = gcd(l_candidate, r_candidate)
            if lower_p <= best_divisor < upper_p:
                return best_divisor
            elif best_divisor > upper_p:
                to_reduce.append(best_divisor)
    for divisor in to_reduce:
        cutoff = divisor // lower_p
        non_divisors = []
        for sub_divisor in range(2, cutoff + 1):
            if any(sub_divisor % non_divisor == 0 for non_divisor in non_divisors):
                continue
            quotient, remainder = gmpy2.c_divmod(divisor, sub_divisor)
            if remainder == 0 and lower_p <= quotient < upper_p:
                return quotient
            if quotient < lower_p:
                break
            if remainder != 0:
                non_divisors.append(sub_divisor)

def is_correct(x1, x2, l, p_prime):
    p_prime_is_good = p_prime >> (l**2 - 1) and not p_prime >> l ** 2
    x1_is_good = (x1 % p_prime) >> (l-1) and not (x1 % p_prime) >> l
    x2_is_good = (x2 % p_prime) >> (l-1) and not (x2 % p_prime) >> l
    return bool(p_prime_is_good and x1_is_good and x2_is_good)

if __name__ == '__main__':
    seed(0)

    l = int(argv[1])
    reps = int(argv[2])

    def randbits(bits):
        return randrange(2 ** (bits - 1), 2 ** bits)

    for _ in range(reps):
        p = randbits(l ** 2)
        print("p = ", p)
        xs = []
        for i in range(2):
            q_i = randbits(l ** 3)
            print("q", i, "=", q_i)
            r_i = randbits(l)
            print("r", i, "=", r_i)
            x_i = q_i * p + r_i
            print("x", i, "=", x_i)
            xs.append(x_i)

        res = solve(xs, l)
        print("answer = ", res)
        print("Correct?", is_correct(xs[0], xs[1], l, res))

यह कोड इस तथ्य पर आधारित है कि r के सभी संभावित मूल्यों के लिए X1 - r का उत्पाद एक से अधिक p होना चाहिए, और x2 - r का उत्पाद भी होना चाहिए। अधिकांश समय दो उत्पादों के gcd लेने में व्यतीत होता है, जिनमें से प्रत्येक में लगभग 60,000,000 बिट्स होते हैं। Gcd, जिसमें केवल लगभग 250,000 बिट्स होते हैं, तब p के उम्मीदवारों को निकालने के लिए एक बार फिर से xr मानों की तुलना में किया जाता है। यदि वे थोड़े बड़े हैं, तो उन्हें उचित सीमा तक कम करने के लिए ट्रायल डिवीजन का उपयोग किया जाता है।

यह Python के लिए gmpy2 लाइब्रेरी पर आधारित है, जो GNU MP लाइब्रेरी के लिए एक पतला आवरण है, जो विशेष रूप से एक अच्छी gcd दिनचर्या है।

यह कोड सिंगल-थ्रेडेड है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.