Những cách chỉ định tạo ngẫu nhiên trong các thử thách


16

Lưu ý : Theo sự đồng thuận về Meta , câu hỏi là chủ đề ở đây.

Trước "điều cần tránh khi viết thử thách" , tôi bắt đầu suy nghĩ về những thách thức liên quan đến việc tạo ngẫu nhiên một số loại đối tượng nhất định.

Đôi khi, tôi muốn đăng một thử thách liên quan đến việc tạo ngẫu nhiên một foo, trong đó

  1. thật dễ dàng để kiểm tra xem một thứ nhất định có phải là một foo không, và
  2. khó hơn một chút để nhanh chóng tạo ra một foo ngẫu nhiên "chất lượng tốt".

Ví dụ, một foo có thể là một ma trận nhị phân trong đó không có phân đoạn gồm 4 bit bằng nhau theo bất kỳ hướng nào. Thật dễ dàng để kiểm tra xem một ma trận nhị phân nhất định có phải là một foo hay không, nhưng việc tạo ra một foo ngẫu nhiên với phân phối trải rộng độc đáo dường như đòi hỏi một thuật toán quay lui hoặc một cái gì đó tương tự.

Dù sao, bây giờ tôi sẽ cần xác định một cách khách quan những gì đủ điều kiện là một foo ngẫu nhiên và tôi muốn nó là "không thể đoán trước" theo nghĩa trực quan rằng khi tôi chạy chương trình nhiều lần, kết quả luôn khác nhau. Cách tiếp cận hạn chế nhất là yêu cầu đầu ra là ngẫu nhiên thống nhất: tất cả các foos hợp lệ có cùng xác suất được tạo. Điều này thường quá hạn chế, vì tôi không biết làm thế nào để tiết kiệm cho việc tạo ra tất cả các foos hợp lệ, loại bỏ trùng lặp và chọn một, điều này nhàm chán và chậm chạp.

Ý tưởng tiếp theo của tôi là yêu cầu tất cả các foos hợp lệ có xác suất dương được tạo ra. Tuy nhiên, điều này có nghĩa là cách tiếp cận sau là hợp lệ: tạo ra một thứ giống như foo ngẫu nhiên (trong ví dụ của chúng tôi là ma trận nhị phân ngẫu nhiên), nếu đó là foo thì trả về nó, nếu không thì trả về một foo được mã hóa cứng (giả sử là ma trận nhận dạng ). Điều này cũng hơi nhàm chán, vì về cơ bản, nó chỉ là một công cụ nhận dạng các foos được xử lý theo một trình tạo ma trận ngẫu nhiên.

Có thể có một định nghĩa chung tốt đẹp cho một foo ngẫu nhiên không thể đoán trước?

TL; DR

Có cách nào tốt để chỉ định một đối tượng được tạo ngẫu nhiên "không thể đoán trước" không khắc phục phân phối nhưng không khuyến khích mã hóa cứng?


Chúng tôi có một định nghĩa chuẩn cho ngẫu nhiên trên meta sẽ cấm mã hóa cứng, nhưng không hạn chế nó cho đến nay hoàn toàn thống nhất.
Geobits

5
Câu hỏi tuyệt vời. Tôi đã tìm thấy trong quá khứ rằng chỉ định ngẫu nhiên là khó khăn . Đặc biệt đối với kịch bản bạn mô tả, cũng có một vấn đề là bạn chỉ có thể tạo ứng viên ngẫu nhiên và làm lại nếu chúng không hợp lệ. Điều đó thậm chí cung cấp cho bạn một phân phối thống nhất, nhưng thời gian chạy không xác định. Khi chỉ định phân phối đồng đều, vấn đề là các giải pháp thực sự không bao giờ thống nhất hoàn hảo . Đây là một vấn đề rất tinh tế. +1
Martin Ender

@MartinEnder Phải, tôi quên cách tiếp cận đó. Tôi có thể không cho phép nó và thuật toán chậm khác với giới hạn thời gian, nhưng chúng vẫn cho phép giải pháp "một foo được mã hóa cứng".
Zgarb

có vẻ như bạn có thể chỉ định CPRNG K3 / K4, hầu hết các ngôn ngữ sẽ có thư viện en.wikipedia.org/wiki/Pseudorandom_number_generator
Ewan

1
@Zgarb một vấn đề lớn với việc không cho phép "Tạo và làm lại" là phần lớn các thư viện RNG của ngôn ngữ làm điều đó.
Nathan Merrill

Câu trả lời:


5

Trả lại một ngàn foos khác nhau

Điều này làm cho nó không thể trả lại giá trị mã hóa cứng và có một nửa golf tốt. Tuy nhiên, một trình tạo foo hợp pháp sẽ có một cơ hội nhỏ để xuất ra các foos trùng lặp trừ khi nó thực sự kiểm tra chúng. Để loại bỏ gánh nặng kiểm tra, tỷ lệ thất bại được kiểm nghiệm theo kinh nghiệm, giả sử là 10%, có thể được chỉ định là chấp nhận được.

Hãy nhận biết nghịch lý sinh nhật , rằng xác suất trùng lặp có thể cao hơn bạn nghĩ. Nếu chỉ có một triệu foos có thể, một nghìn foos ngẫu nhiên sẽ có xác suất khoảng 0,6 có một bản sao ở đó ở đâu đó và giả sử rằng thế hệ foo hoàn toàn đồng nhất. Nếu đây có thể là một vấn đề, yêu cầu 900 foos duy nhất cho mỗi 1000 được tạo, điều này hào phóng hơn nhiều đối với một trình tạo foo chính hãng nhưng vẫn không thực tế đối với mã hóa cứng.

Điều này cũng cho phép bạn liên tục tạo ra những thứ giống như foo và kiểm tra fooness cho đến khi bạn nhận được foos. Tôi nghĩ rằng đây là một giải pháp hợp lệ, nhưng nếu bạn không thích nó:

Làm nhanh lên

Cơ hội của một thứ giống như foo hoàn toàn ngẫu nhiên là foo có lẽ là khá thấp, vì vậy việc chỉ định giới hạn thời gian có khả năng buộc một nỗ lực thực sự ở thế hệ foo.

Để điều chỉnh sự khác biệt về tốc độ giữa các ngôn ngữ khác nhau, bạn có thể muốn có các giới hạn thời gian khác nhau tùy thuộc vào ngôn ngữ như Hackerrank: https://www.hackerrank.com/en môi trường . Tuy nhiên, nếu bạn chỉ định foos đủ lớn, xác suất của những thứ giống như foo ngẫu nhiên là foo có thể rất thấp, do đó, quy tắc "trước cái chết nóng của vũ trụ" có thể là đủ.


Tôi nghĩ rằng bạn đang ở một cái gì đó ở đây. "Chạy chương trình N lần sẽ không tạo ra bản sao ít nhất 90% thời gian" là thử nghiệm cụ thể và khá dễ dàng, và nó có thể được kết hợp với thời gian bị ràng buộc để ngăn chặn cưỡng bức và lấy mẫu từ chối đơn giản.
Zgarb

2

Tôi không khẳng định có giải pháp tối ưu cho vấn đề (hoặc danh sách này là toàn diện), nhưng tôi muốn phác thảo một số cách tiếp cận có thể xuất hiện trong đầu và tại sao chúng sẽ hoặc không hoạt động. Tôi cũng sẽ không giải quyết các vấn đề tiếp theo như liệu sử dụng dấu thời gian hiện tại làm nguồn ngẫu nhiên có đủ "không thể đoán trước" hay không và làm thế nào để thực thi một số tính chất của phân phối xác suất - Tôi sẽ chỉ tập trung vào việc tránh các giải pháp sử dụng mã hóa.

Không phải là một giải pháp: không cho phép mã hóa cứng

Đây là một ý tưởng tồi. Đó là một yêu cầu không thể quan sát được (có nghĩa là bạn không thể xác định liệu nó có hài lòng chỉ bằng cách chạy chương trình hay không), điều này không được khuyến khích mạnh mẽ trên PPCG và có thể hoàn toàn không thể nếu chạy chương trình trên bất kỳ nền tảng nào khác, nơi đệ trình được xác minh trong cách tự động. Vấn đề với một yêu cầu như thế này là bạn phải bắt đầu bằng cách tìm một định nghĩa khách quan cho "mã hóa cứng". Nói chung, nếu bạn thử điều này, bạn sẽ chỉ làm mọi thứ tồi tệ hơn.

Làm cho mã hóa cứng không khả thi

Nếu bạn không thể không cho phép nó hoàn toàn, nhưng bạn không muốn mọi người sử dụng nó, thì bạn có thể thử thiết kế thử thách sao cho mã hóa đơn giản không phải là một cách tiếp cận cạnh tranh. Điều này là có thể nếu các đối tượng nên được tạo ra đủ lớn và không thể nén được, việc đưa một ví dụ vào mã sẽ đòi hỏi nhiều byte hơn so với việc viết một thuật toán tạo ra các giải pháp hợp lệ một cách ngẫu nhiên. Trong ví dụ cụ thể của bạn, đó không phải là trường hợp tất nhiên, vì ma trận danh tính là hợp lệ và thường dễ tạo ra, nhưng đối với các vấn đề khác, điều đó có thể không phải là trường hợp. Nếu các đối tượng đích đủ bất thường, chỉ cần yêu cầu chúng có kích thước lớn, điều này có thể sẽ không ảnh hưởng đến số byte của thuật toán thực tế nhưng sẽ làm nổ tung phần mã hóa cứng.

Tham số hóa đầu ra

Thông thường, những vấn đề này đi kèm với một hoặc nhiều tham số tự nhiên, như kích thước của ma trận trong ví dụ của bạn. Nếu vậy, làm cho tham số đó trở thành đầu vào có thể đủ để làm cho mã hóa cứng không thể hoặc ít nhất là không thực tế. Trong một số trường hợp, có thể dễ dàng mã hóa một giải pháp cụ thể cho một giá trị tham số đã cho được tìm thấy bằng tay hoặc thông qua tìm kiếm mở rộng, nhưng có thể không có dạng đóng đơn giản cho một thể hiện của giải pháp này nói chung, vì vậy nó không phải là có thể tạo ra một giá trị mặc định cho các đầu vào tùy ý một cách dễ dàng. Một lần nữa, đây không phải là trường hợp ví dụ bạn đề cập, bởi vì ma trận danh tính hoạt động ở mọi kích thước, nhưng là một giải pháp tối ưu cho vấn đề liên quan nàythường rất bất thường, vì vậy dù sao cũng không thể có giá trị mặc định mà không chủ động tìm kiếm các giá trị hợp lệ. Bạn có thể kết hợp điều này với một giới hạn thời gian để tránh tìm kiếm vũ phu cho một giá trị mặc định.

Đặt một số hạn chế về phân phối xác suất

Nếu bạn sẵn sàng từ bỏ phân phối xác suất hoàn toàn không bị hạn chế, bạn có thể đặt một số ràng buộc cho nó, điều đó vẫn mang lại cho người trả lời rất nhiều sự tự do trong việc lựa chọn phân phối của họ nhưng điều đó làm cho việc mã hóa khó khăn trở nên khó khăn hoặc không thể:

  • Ràng buộc đơn giản nhất xuất hiện trong đầu là yêu cầu chênh lệch giữa xác suất tối thiểu và tối đa cho bất kỳ đầu ra có thể nào nằm dưới một ngưỡng nhất định. Một cách tiếp cận được mã hóa cứng có thể sẽ có xác suất gần như bằng không cho hầu hết tất cả các kết quả đầu ra và xác suất gần bằng 1 cho giá trị mặc định. Nếu bạn yêu cầu mức chênh lệch tối đa dưới 0,1, thì sẽ cần có 10 giá trị mặc định (được chọn ngẫu nhiên) để làm cho cách tiếp cận trở thành một tùy chọn. Tương tự, bạn cũng có thể chỉ yêu cầu xác suất tối thiểu cho mỗi đầu ra có thể, ví dụ 1 / (2 * N *), trong đó N là số lượng đầu ra có thể.
  • Ngoài ra, bạn có thể yêu cầu rằng không có (khả năng) những lỗ hổng trong việc phân phối, do đó không có khoảng thời gian kích thước δ (được lựa chọn bởi bạn) sao cho cả hai xác suất cao hơn và thấp hơn tồn tại. Điều đó có nghĩa là không thể có bất kỳ ngoại lệ nào về khả năng, có khả năng được tạo ra bởi một phương pháp mã hóa cứng.

Vấn đề chính với những cách tiếp cận này là chúng khó lý luận hơn rất nhiều, việc chứng minh tính chính xác của câu trả lời là khó khăn và việc kiểm chứng bằng thực nghiệm có thể là không thể đối với không gian đầu ra lớn. Tuy nhiên, họ cung cấp một yêu cầu chủ yếu có thể quan sát được cho chương trình có thể khiến việc mã hóa không thể thực hiện được.

Các cách tiếp cận này cũng có thể cần giới hạn thời gian, bởi vì một cách để tăng xác suất của các giá trị không mặc định sẽ là cố gắng tìm một foo ngẫu nhiên nhiều lần trước khi quay trở lại giá trị mặc định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.