質問編集履歴

1

追加

2020/11/12 22:26

投稿

apeirogon0813
apeirogon0813

スコア117

test CHANGED
File without changes
test CHANGED
@@ -183,3 +183,361 @@
183
183
 
184
184
 
185
185
  ご教示願います。
186
+
187
+
188
+
189
+ ```python
190
+
191
+ import random
192
+
193
+ import networkx as nx
194
+
195
+ import matplotlib.pyplot as plt
196
+
197
+ import copy
198
+
199
+
200
+
201
+ #要素が重複しているか
202
+
203
+ def has_duplicates(seq):
204
+
205
+ return len(seq) == len(set(seq))
206
+
207
+
208
+
209
+ def create_volumes(n):
210
+
211
+ #重複しないレコードの作成
212
+
213
+ V = random.sample(range(5,260), k=n)
214
+
215
+ #観測されるボリューム集合の生成
216
+
217
+ W = copy.copy(V)
218
+
219
+ for i in range(N-1):
220
+
221
+ W.append(V[i]+V[i+1])
222
+
223
+ return V, W
224
+
225
+
226
+
227
+ #候補解から生成されるボリュームを観測したボリュームと比較
228
+
229
+ def compare_volumes(S, W):
230
+
231
+ T = set()
232
+
233
+ #観測されるボリューム集合の生成
234
+
235
+ for s in S:
236
+
237
+ w = copy.copy(s)
238
+
239
+ for i in range(N-1):
240
+
241
+ w.append(s[i]+s[i+1])
242
+
243
+ if set(w) == set(W):
244
+
245
+ #print(tuple(s))
246
+
247
+ T.add(tuple(s))
248
+
249
+ return T
250
+
251
+
252
+
253
+
254
+
255
+ #1つ以上重複しているボリュームを作成(レコードは重複していない)
256
+
257
+ def create_duplicates(n):
258
+
259
+ data = create_volumes(n)
260
+
261
+ if has_duplicates(data[1]): #重複していないならば
262
+
263
+ return create_duplicates(n)
264
+
265
+ else:
266
+
267
+ return data
268
+
269
+
270
+
271
+ def create_no_duplicates(n):
272
+
273
+ data = create_volumes(n)
274
+
275
+ #print(data[1])
276
+
277
+ if has_duplicates(data[1]):
278
+
279
+ return data
280
+
281
+ else:
282
+
283
+ return create_duplicates(n)
284
+
285
+
286
+
287
+
288
+
289
+ Ans = []
290
+
291
+ N = 26 #攻撃者は既知
292
+
293
+ result = create_duplicates(N)
294
+
295
+ #result = create_no_duplicates(N)
296
+
297
+ V = result[0] #復元したいレコード
298
+
299
+ print("V = " + str(V))
300
+
301
+ print("W = " + str(result[1]))
302
+
303
+ W = list(set(result[1])) #攻撃者が観測するボリュームの集合
304
+
305
+
306
+
307
+
308
+
309
+ #要素を昇順に
310
+
311
+ W.sort()
312
+
313
+ print("昇順W = " + str(W) + " ( |W| = " + str(len(W)) +" )")
314
+
315
+
316
+
317
+ G = nx.Graph()
318
+
319
+ #step1 2頂点の和がボリュームに含まれているのならエッジを追加
320
+
321
+ #連結しているて頂点のみをエッジごと抽出
322
+
323
+ n = len(W)
324
+
325
+ for i in range(n-2):
326
+
327
+ for j in range(i+1,n-1):
328
+
329
+ if W[i] + W[j] in W:
330
+
331
+ G.add_edge(W[i], W[j])
332
+
333
+
334
+
335
+ print("存在する枝 = " + str(G.edges))
336
+
337
+ print("抽出されたボリューム(" + str(len(G.nodes)) +"/" + str(len(W)) +") = " + str(G.nodes))
338
+
339
+ print(list(G.neighbors(W[0])))
340
+
341
+
342
+
343
+ #step2 確定レコード選別する
344
+
345
+ RNodes = [W[0], W[1]] #レコードは重複しない仮定より1,2番目に小さいボリュームはレコードである
346
+
347
+ for i in range(2, N):
348
+
349
+ for j in range(i):
350
+
351
+ #print("W[i] - W[j] = " + str(W[i]) + " - " + str(W[j]))
352
+
353
+ if W[i] - W[j] in W and W[i] != 2 * W[j] : #あるボリュームが確定レコード同士の和である時(その要素が隣同士orレコードであるor両方)
354
+
355
+ break
356
+
357
+ #else: 和でない場合は次に進める
358
+
359
+ #最終的にそのボリュームを生成する確定レコードの2要素の和が存在しない場合、そのボリューム確定レコード
360
+
361
+ if j == i-1:
362
+
363
+ RNodes.append(W[i])
364
+
365
+
366
+
367
+ print("確定レコード = " + str(RNodes))
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+ #step3 確定レコードである頂点を通る経路長=N-1である経路
376
+
377
+ S = []
378
+
379
+ #//集合の中にリストの集合
380
+
381
+ l = list(G.neighbors(W[0]))
382
+
383
+
384
+
385
+ for i in l: #一次元配列だとループが回せないため、二次元配列にしておく
386
+
387
+ S.append([W[0],i])
388
+
389
+
390
+
391
+ def right_shift(S,G):
392
+
393
+ #print("S = " + str(S))
394
+
395
+ for i in range(N-2): #解の長さがNになるまで
396
+
397
+ T = []
398
+
399
+ for s in S: #解の数
400
+
401
+ if len(s) != N:
402
+
403
+ right_num = len(s) - 1
404
+
405
+ l = list(G.neighbors(s[right_num]))#一番右の要素と隣合うノードを取得
406
+
407
+ for node in l:
408
+
409
+ if node not in s: #同じレコードは存在しないかの判定
410
+
411
+ C = copy.copy(s)
412
+
413
+ C.append(node)
414
+
415
+ if C not in T:
416
+
417
+ T.append(C)
418
+
419
+ T.append(s)#右に拡張できるがそのノードが終点である可能性があるため
420
+
421
+ #print(T)
422
+
423
+ S = copy.copy(T)
424
+
425
+ #print("S = " + str(S))
426
+
427
+ return S
428
+
429
+
430
+
431
+ #S = right_shift(S)
432
+
433
+
434
+
435
+ #左に拡張
436
+
437
+ def left_shift(S,G):
438
+
439
+ for i in range(N-2):
440
+
441
+ T = []
442
+
443
+ for s in S:
444
+
445
+ #print("s = " + str(s))
446
+
447
+ if len(s) != N:
448
+
449
+ l = list(G.neighbors(s[0]))
450
+
451
+ for node in l:
452
+
453
+ if node not in s: #同じレコードは存在しないかの判定
454
+
455
+ C = copy.copy(s)
456
+
457
+ C.insert(0,node) #先頭に要素を追加
458
+
459
+ if C not in T:
460
+
461
+ T.append(C)
462
+
463
+ T.append(s)
464
+
465
+ S = copy.copy(T)
466
+
467
+ #print("s = " + str(S))
468
+
469
+ return S
470
+
471
+
472
+
473
+ #step4 確定コードが解に含まれているか 現段階では確定レコードを通る効率的なアルゴリズムが考えられていないため
474
+
475
+ def confirm(S):
476
+
477
+ T = []
478
+
479
+ for s in S:
480
+
481
+ if len(s) == N:
482
+
483
+ for i in range(len(RNodes)):
484
+
485
+ if RNodes[i] not in s:
486
+
487
+ break
488
+
489
+ if i == len(RNodes)-1:
490
+
491
+ T.append(s)
492
+
493
+ return T
494
+
495
+ T = copy.copy(S)
496
+
497
+ T = right_shift(T,G)
498
+
499
+ T = left_shift(T,G)
500
+
501
+ S = left_shift(S,G)
502
+
503
+ S = right_shift(S,G)
504
+
505
+ #print("解候補 = " + str(T))
506
+
507
+ print("解の数1 = " + str(len(T)))
508
+
509
+ T = confirm(T)
510
+
511
+ S = confirm(S)
512
+
513
+ #print("解候補選別T = " + str(T))
514
+
515
+ #print("解候補選別S = " + str(S))
516
+
517
+ print("解の数2 = " + str(len(T)))
518
+
519
+
520
+
521
+
522
+
523
+ #step5 解からボリュームを計算し比較
524
+
525
+ G1 = compare_volumes(T, W)
526
+
527
+ #print("G1 = " + str(G1))
528
+
529
+ G2 = compare_volumes(S, W)
530
+
531
+ #print("G2 = " + str(G2))
532
+
533
+ G3 = G1|G2
534
+
535
+
536
+
537
+ print("候補解(" + str(len(G3)) + "個) = " + str(G3))
538
+
539
+ print("真の解 = " + str(V))
540
+
541
+
542
+
543
+ ```