Advertisement
Guest User

constraintSolver.py

a guest
Nov 27th, 2022
846
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.90 KB | None | 0 0
  1. from enum import Enum
  2. class St(Enum):
  3.     THEFT = 0
  4.     LEAKED = 1
  5.     LOST = 2
  6.     SAFE = 3
  7.  
  8. # THEFT is the worst, SAFE is the best. LEAKED and LOST undefined.
  9. # False doesn't necessarily imply "not worse or equal".
  10. def worse_or_equal(st1, st2): # self is worse or equal than other
  11.     if st1 == St.THEFT or st2 == St.SAFE:
  12.         return True
  13.     return False
  14.  
  15. class Scenario():
  16.     def __init__(self, n, arr):
  17.         self.n = n
  18.         self.credentials = arr
  19.         self.safe = 0
  20.         self.leaked = 0
  21.         self.lost = 0
  22.         self.theft = 0
  23.         for i in self.credentials:
  24.             if i == St.SAFE:
  25.                 self.safe = self.safe + 1
  26.             if i == St.THEFT:
  27.                 self.theft = self.theft + 1
  28.             if i == St.LEAKED:
  29.                 self.leaked = self.leaked + 1
  30.             if i == St.LOST:
  31.                 self.lost = self.lost + 1
  32.  
  33.     def __repr__(self):
  34.         return "Scenario: %s" % (self.credentials)
  35.    
  36.     def __eq__(self, other):
  37.         return self.n == other.n and self.credentials == other.credentials
  38.    
  39.     def priority_rule(self, rule: [int]) -> bool:
  40.         for x in rule:
  41.             if self.credentials[x] == St.SAFE:
  42.                 return True # User wins
  43.             elif self.credentials[x] == St.THEFT:
  44.                 return False # Attacker wins
  45.         return False # Corner case (no safe, theft)
  46.    
  47.     # Exception is (rule[1]) < (rule[2])
  48.     def priority_rule_with_exception(self, rule:[int]) -> bool:
  49.         if self.credentials[rule[0]] == St.LOST:
  50.             if self.credentials[rule[1]] == St.SAFE and self.credentials[rule[2]] == St.THEFT:
  51.                 return False
  52.             if self.credentials[rule[1]] == St.THEFT and self.credentials[rule[2]] == St.SAFE:
  53.                 return True
  54.         for x in rule:
  55.             if self.credentials[x] == St.SAFE:
  56.                 return True # User wins
  57.             elif self.credentials[x] == St.THEFT:
  58.                 return False # Attacker wins
  59.         return False # Corner case (no safe, theft)
  60.  
  61.     def is_complement(self, other) -> bool:
  62.         if self.n != other.n:
  63.             return False
  64.         for idx, cred in enumerate(self.credentials):
  65.             if cred == St.SAFE and other.credentials[idx] != St.THEFT:
  66.                 return False
  67.             if cred == St.THEFT and other.credentials[idx] != St.SAFE:
  68.                 return False
  69.             if cred == St.LEAKED and other.credentials[idx] != St.LEAKED:
  70.                 return False
  71.             if cred == St.LOST and other.credentials[idx] != St.LOST:
  72.                 return False
  73.         return True
  74.  
  75.     # Returns true only if for all credentials are worse or equal. In all other cases, returns false.
  76.     def worse_or_equal(self, other) -> bool:
  77.         if self.n != other.n:
  78.             return False
  79.         for i in range(self.n):
  80.             if not worse_or_equal(self.credentials[i], other.credentials[i]):
  81.                 return False
  82.         return True
  83.  
  84. def complement(s: Scenario):
  85.     scomp = []
  86.     for cred in s.credentials:
  87.         if cred == St.LEAKED:
  88.             scomp.append(St.LEAKED)
  89.         elif cred == St.LOST:
  90.             scomp.append(St.LOST)
  91.         elif cred == St.SAFE:
  92.             scomp.append(St.THEFT)
  93.         else:
  94.             scomp.append(St.SAFE)
  95.     return Scenario(s.n, scomp)
  96.  
  97. scenario1 = Scenario(2, [St.SAFE, St.LEAKED])
  98.  
  99. import copy
  100. from copy import deepcopy
  101. import itertools
  102. def recurse(n):
  103.     if n == 1:
  104.         return [Scenario(1, [St.THEFT]),
  105.                 Scenario(1, [St.LEAKED]),
  106.                 Scenario(1, [St.LOST]),
  107.                 Scenario(1, [St.SAFE])]
  108.  
  109.     ret = recurse(n-1)
  110.     # print(n, ret)
  111.     final = []
  112.     for st in St:
  113.         for s in ret:
  114.             creds1 = copy.deepcopy(s.credentials)
  115.             creds1.append(st)
  116.             final.append(Scenario(n, creds1))
  117.     return final
  118.  
  119. num_creds = 3
  120. all_scenarios = recurse(num_creds)
  121.  
  122. def is_special(s: Scenario):
  123.     num_safe = 0
  124.     num_theft = 0
  125.     for cred in s.credentials:
  126.         if cred == St.SAFE:
  127.             num_safe = num_safe + 1
  128.         elif cred == St.THEFT:
  129.             num_theft = num_theft + 1
  130.     return num_safe > 0 and num_theft > 0
  131.  
  132. special_scenarios = []
  133.  
  134. for s in all_scenarios:
  135.     if is_special(s):
  136.         special_scenarios.append(s)
  137.  
  138. print(len(all_scenarios))
  139. print(len(special_scenarios))
  140.  
  141. # Step 1. List all optimal profiles
  142. # Step 2. Try to find a profile incomparable to all and satisfying some constraints
  143.  
  144. optimal_profiles = []
  145.  
  146. majority_profile_prefix = [Scenario(3, [St.SAFE, St.SAFE, St.THEFT]),
  147.                            Scenario(3, [St.SAFE, St.THEFT, St.SAFE]),
  148.                            Scenario(3, [St.THEFT, St.SAFE, St.SAFE])]
  149.  
  150. rest = [Scenario(3, [St.SAFE, St.LEAKED, St.THEFT]),
  151.         Scenario(3, [St.LEAKED, St.THEFT, St.SAFE]),
  152.         Scenario(3, [St.THEFT, St.SAFE, St.LEAKED]),
  153.         Scenario(3, [St.SAFE, St.LOST, St.THEFT]),
  154.         Scenario(3, [St.LOST, St.THEFT, St.SAFE]),
  155.         Scenario(3, [St.THEFT, St.SAFE, St.LOST])]
  156.  
  157. # Test
  158. for x in majority_profile_prefix:
  159.     if not (x in special_scenarios):
  160.         print("Terror")
  161. for x in rest:
  162.     if not (x in special_scenarios):
  163.         print("Terror")
  164.  
  165. majority_profiles = []
  166.  
  167. for v in itertools.product('01', repeat=len(rest)):
  168.     profile = deepcopy(majority_profile_prefix)
  169.     for i, scenario in enumerate(rest):
  170.         if v[i] == '1':
  171.             scenario = complement(scenario)
  172.         profile.append(scenario)
  173.     # print(profile)
  174.     majority_profiles.append(profile)
  175.  
  176. print("#majority profiles:", len(majority_profiles))
  177.  
  178. priority_profiles = []
  179.  
  180. for rule in itertools.permutations([0, 1, 2]):
  181.     profile1 = [] # normal
  182.     profile2 = [] # exception
  183.     for scenario in special_scenarios:
  184.         if scenario.priority_rule(rule):
  185.             profile1.append(deepcopy(scenario))
  186.         if scenario.priority_rule_with_exception(rule):
  187.             profile2.append(deepcopy(scenario))
  188.     priority_profiles.append(profile1)
  189.     priority_profiles.append(profile2)
  190.  
  191. print("#priority profiles:", len(priority_profiles))
  192.  
  193. for p in majority_profiles:
  194.     assert(len(p)) == len(special_scenarios) / 2
  195.     optimal_profiles.append(p)
  196.  
  197. for p in priority_profiles:
  198.     assert(len(p)) == len(special_scenarios) / 2
  199.     optimal_profiles.append(p)
  200.  
  201. # Test
  202. for idx1, profile1 in enumerate(optimal_profiles):
  203.     for idx2, profile2 in enumerate(optimal_profiles):
  204.         if idx1 != idx2 and profile1 == profile2:
  205.             print("Terror")
  206.  
  207.  
  208. # not really all possible profiles.. more like all possible special scenarios in prof(M), denoted by S
  209. all_possible_profiles = []
  210.  
  211. half_special_scenarios = []
  212. complements = []
  213. for s in majority_profile_prefix:
  214.     half_special_scenarios.append(deepcopy(s))
  215.     complements.append(complement(s))
  216. for s in rest:
  217.     half_special_scenarios.append(deepcopy(s))
  218.     complements.append(complement(s))
  219.  
  220. assert len(half_special_scenarios) == len(special_scenarios) / 2
  221.  
  222. for v in itertools.product([0, 1, 2], repeat=len(half_special_scenarios)):
  223.     profile = []
  224.     for idx, x in enumerate(v):
  225.         if x == 1:
  226.             profile.append(half_special_scenarios[idx])
  227.         elif x == 2:
  228.             profile.append(complements[idx])
  229.     if len(profile) == 0:
  230.         continue
  231.     all_possible_profiles.append(profile)
  232.  
  233. assert len(all_possible_profiles) == 3**(len(special_scenarios) / 2) - 1
  234.  
  235. # print(all_possible_profiles[0], all_possible_profiles[-1])
  236.  
  237. def intersection(lst1, lst2):
  238.     lst3 = [value for value in lst1 if value in lst2]
  239.     return lst3
  240.  
  241. # P(M) must contain at least one of the complements of the special scenarios in order to be incomparable.
  242. # The implementation is doing a complement of all scenarios, which is not required, but not wrong either.
  243. def no_clashes(profile: [Scenario]) -> bool:
  244.     for opt in optimal_profiles:
  245.         c = []
  246.         # print(opt)
  247.         for s in opt:
  248.             c.append(complement(s))
  249.         # print(c)
  250.         if len(intersection(c, profile)) == 0:
  251.             return False
  252.     return True
  253.  
  254. # Checks if the profile contains scenarios s1 and s2 s.t. complement(s2) is worse than s1.
  255. def is_valid_profile(profile: [Scenario]) -> bool:
  256.     for s in profile:
  257.         c = complement(s) # c is won by the attacker (because it is a complement)
  258.         for s1 in profile: # finding a scenario that is worse than c and won by the user
  259.             if s1.worse_or_equal(c):
  260.                 return False
  261.     return True
  262.  
  263. from constraint import *
  264.  
  265. def constraintSolve():
  266.     problem = Problem()
  267.     problem.addVariable("s", all_possible_profiles)
  268.     problem.addConstraint(no_clashes, "s")
  269.     problem.addConstraint(is_valid_profile, "s")
  270.     solutions = problem.getSolutions()
  271.     print(len(solutions))
  272.     if len(solutions) > 0:
  273.         print(solutions[0])
  274.  
  275. if __name__ == '__main__':
  276.     constraintSolve()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement