model-checker 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2024 Benjamin Brast-McKie
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: model_checker
3
+ Version: 0.1
4
+ Summary: A hyperintensional model checker for counterfactual conditionals
5
+ Author-email: Benjamin Brast-McKie <benbrastmckie@gmail.com>, Miguel Buitrago <mfbuit46@mit.edu>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/benbrastmckie/ModelChecker
8
+ Project-URL: Issues, https://github.com/benbrastmckie/ModelChecker/issues
9
+ Keywords: semantics,Z3,counterfactuals,model checker
10
+ Classifier: Programming Language :: Python :: 3.8
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENCE
15
+ Requires-Dist: z3-solver
16
+
@@ -0,0 +1,11 @@
1
+ package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ package/model_definitions.py,sha256=HbsOCBxRRG86ylBEw2XK5t1hzYxlLrFmsZW3NYtBqw0,10290
3
+ package/model_structure.py,sha256=PCvxwji4_z8l_N2PBoKBYs6kxO8sXfvxvUKfXZAcRXU,19408
4
+ package/semantics.py,sha256=MJnufO4EivSECv5yUtVPz30UWcSw7Fqz23qKHHK8YaQ,19261
5
+ package/syntax.py,sha256=H2TyLhXz8WNXZfocqoWNNAr1eXk1YEaRQ2e23cqy-Y0,6776
6
+ package/test_complete.py,sha256=lu9HjS7ZHQBaPws0k8TX21nW2FKKfmzxcCODWCNL50Y,3932
7
+ model_checker-0.1.dist-info/LICENCE,sha256=1b7pP-AWYWwdmQvnAd2F4oWWP2zuFwBk4fFju8Jnm94,1064
8
+ model_checker-0.1.dist-info/METADATA,sha256=ZB0du4IZTSc9ZJkhPm8lOrLDYMympELrp0QxxS5fA_s,671
9
+ model_checker-0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
10
+ model_checker-0.1.dist-info/top_level.txt,sha256=TpQW7893uEAT8mPh-QCMZWhhKYvlqryC9Fjm5Hxg2f8,8
11
+ model_checker-0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.43.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ package
package/__init__.py ADDED
File without changes
@@ -0,0 +1,258 @@
1
+ '''
2
+ file contains all definitions for defining the model structure
3
+ '''
4
+
5
+ from z3 import (
6
+ BitVecVal, simplify,
7
+ )
8
+
9
+ from syntax import Infix
10
+
11
+ def summation(n, func, start = 0):
12
+ '''summation of i ranging from start to n of func(i)
13
+ used in find_all_bits'''
14
+ if start == n:
15
+ return func(start)
16
+ return func(start) + summation(n,func,start+1)
17
+
18
+ def find_all_bits(size):
19
+ '''extract all bitvectors from the input model
20
+ imported by model_structure'''
21
+ all_bits = []
22
+ max_bit_number = summation(
23
+ size + 1, lambda x: 2**x
24
+ ) # this should hopefully be enough to cover all states
25
+ for val in range(max_bit_number):
26
+ test_bit = BitVecVal(val, size)
27
+ if test_bit in all_bits:
28
+ # break once bits start to repeat
29
+ continue
30
+ all_bits.append(test_bit)
31
+ return all_bits
32
+
33
+
34
+ def find_poss_bits(model,all_bits, possible):
35
+ '''extract all possible bitvectors from all_bits given the model
36
+ imported by model_structure'''
37
+ poss_bits = []
38
+ for bit in all_bits:
39
+ if model.evaluate(possible(bit)): # of type/sort BoolRef
40
+ poss_bits.append(bit)
41
+ return poss_bits
42
+
43
+
44
+ def find_world_bits(poss_bits):
45
+ '''finds the world bits from a list of possible bits.
46
+ used in print_states() and find_relations()'''
47
+ not_worlds = []
48
+ for potential_world in poss_bits:
49
+ if potential_world in not_worlds:
50
+ continue
51
+ for test in poss_bits:
52
+ if bit_part(test, potential_world):
53
+ continue
54
+ if bit_proper_part(potential_world, test):
55
+ not_worlds.append(potential_world)
56
+ break
57
+ world_bits = [world for world in poss_bits if world not in not_worlds]
58
+ # for world in world_bits:
59
+ # print(model.evaluate(is_world(world)))
60
+ # if not model.evaluate(is_world(world)):
61
+ # raise ValueError(f'{world} was in world_bits but is not a world per the model')
62
+ # for not_world in not_worlds:
63
+ # print(model.evaluate(is_world(not_world)))
64
+ # # if model.evaluate(is_world(not_world)):
65
+ # # raise ValueError(f'{not_world} was not in world_bits but is a world per the model')
66
+ return world_bits
67
+
68
+
69
+ def find_compatible_parts(verifier_bit, poss_bits, eval_world):
70
+ """
71
+ Finds the parts of the eval_world compatible with the verifier_bit.
72
+ Used in find_alt_bits()
73
+ """
74
+ comp_parts = []
75
+ for part in poss_bits:
76
+ if bit_fusion(verifier_bit, part) in poss_bits and bit_part(part, eval_world):
77
+ comp_parts.append(part)
78
+ # ie, if fusion is possible and the bit part is in the eval_world
79
+ return comp_parts
80
+
81
+
82
+ def find_max_comp_ver_parts(verifier_bit, comp_parts):
83
+ """
84
+ Finds a list of fusions of the verifier_bit and a maximal compatible part.
85
+ Used in find_alt_bits(), immediately after find_compatible_parts() above.
86
+ """
87
+ not_max_comp_part = []
88
+ for max_part in comp_parts:
89
+ for test in comp_parts:
90
+ if bit_proper_part(max_part, test):
91
+ not_max_comp_part.append(max_part)
92
+ break # continues with the first for loop
93
+ max_comp_parts = [part for part in comp_parts if part not in not_max_comp_part]
94
+ max_comp_ver_parts = [bit_fusion(verifier_bit, max) for max in max_comp_parts]
95
+ return max_comp_ver_parts
96
+
97
+ def relate_sents_and_states(all_bits, sentence, model, relation):
98
+ """helper function for finding verifier and falsifier states to sentences in a model
99
+ Used in find_relations()
100
+ DOES NOT CHECK IF THESE ARE POSSIBLE. """
101
+ relation_set = set()
102
+ for bit in all_bits:
103
+ if model.evaluate(relation(bit, model[sentence])):
104
+ relation_set.add(bit)
105
+ return relation_set
106
+
107
+ def find_true_and_false_in_alt(alt_bit, parent_model_structure):
108
+ """returns two sets as a tuple, one being the set of sentences true in the alt world and the other the set being false.
109
+ Used in Proposition class print_alt_worlds"""
110
+ extensional_sentences = parent_model_structure.extensional_subsentences
111
+ all_bits = parent_model_structure.all_bits
112
+ true_in_alt = []
113
+ for R in extensional_sentences:
114
+ for bit in all_bits:
115
+ # print(model.evaluate(extended_verify(bit, R, evaluate=True), model_completion=True))
116
+ # print(type(model.evaluate(extended_verify(bit, R, evaluate=True), model_completion=True)))
117
+ if bit in parent_model_structure.find_complex_proposition(R)[0] and bit_part(bit, alt_bit):
118
+ true_in_alt.append(R)
119
+ break # returns to the for loop over sentence_letters
120
+ false_in_alt = [R for R in extensional_sentences if not R in true_in_alt] # replace with
121
+ return (true_in_alt, false_in_alt)
122
+
123
+
124
+ def make_set_pretty_for_print(set_with_strings):
125
+ """input a set with strings
126
+ print that same set but with no quotation marks around each individual string, and also with the set in order
127
+ returns the set as a string
128
+ Used in print_vers_and_fals() and print_alt_worlds()"""
129
+ sorted_set = sorted(list(set_with_strings)) # actually type list, not set
130
+ print_str = "{"
131
+ for i, elem in enumerate(sorted_set):
132
+ print_str += elem
133
+ if i != len(sorted_set) - 1:
134
+ print_str += ", "
135
+ print_str += "}"
136
+ return print_str
137
+
138
+ def product(set_A, set_B):
139
+ product_set = set()
140
+ for a in set_A:
141
+ for b in set_B:
142
+ product_set.add(bit_fusion(a,b))
143
+ return product_set
144
+
145
+ def coproduct(set_A, set_B):
146
+ A_U_B = set_A.union(set_B)
147
+ return A_U_B.union(product(set_A, set_B))
148
+
149
+ def atomic_propositions_dict(all_bits, sentence_letters, model, verify, falsify):
150
+ atomic_VFs_dict = {}
151
+ for letter in sentence_letters:
152
+ ver_bits = relate_sents_and_states(all_bits, letter, model, verify)
153
+ fal_bits = relate_sents_and_states(all_bits, letter, model, falsify)
154
+ atomic_VFs_dict[letter] = (ver_bits, fal_bits)
155
+ return atomic_VFs_dict
156
+
157
+ def print_alt_relation(alt_relation_set, alt_bit, relation_truth_value, N):
158
+ """true is a string representing the relation ("true" for true_in_alt; m.m. for false) that is being used for
159
+ alt_relation_set is the set of prefix sentences that have truth value relation_truth_value in a
160
+ given alternative world alt_bit
161
+ returns None, only prints
162
+ Used in print_alt_worlds()"""
163
+ if not alt_relation_set:
164
+ return
165
+ alt_relation_list = sorted([Infix(sent) for sent in alt_relation_set])
166
+ alt_relation_string = ", ".join(alt_relation_list)
167
+ if len(alt_relation_set) == 1:
168
+ print(f" {alt_relation_string} is {relation_truth_value} in {bitvec_to_substates(alt_bit, N)}")
169
+ else:
170
+ print(f" {alt_relation_string} are {relation_truth_value} in {bitvec_to_substates(alt_bit, N)}")
171
+
172
+
173
+ #############################################
174
+ ######### MOVED FROM DEFINITIONS.PY #########
175
+ #############################################
176
+
177
+
178
+
179
+ def bit_fusion(bit_s, bit_t):
180
+ """the result of taking the maximum for each index in _s and _t"""
181
+ return simplify(bit_s | bit_t)
182
+ # NOTE: this does seem to make a difference, otherwise no comp_parts
183
+
184
+ def bit_part(bit_s, bit_t):
185
+ """the fusion of _s and _t is identical to bit_t"""
186
+ return bool(simplify(bit_fusion(bit_s, bit_t) == bit_t))
187
+ # NOTE: this does seem to make a difference, otherwise no comp_parts
188
+
189
+ def bit_proper_part(bit_s, bit_t):
190
+ """bit_s is a part of bit_t and bit_t is not a part of bit_s"""
191
+ return bool(bit_part(bit_s, bit_t)) and not bit_s == bit_t
192
+ # NOTE: this does not seem to make a difference and so has been turned off
193
+ # in the interest of discovering if it is required or not
194
+ # return bool(bit_part(bit_s, bit_t)) and not bit_s == bit_t
195
+
196
+ def index_to_substate(index):
197
+ '''
198
+ test cases should make evident what's going on
199
+ >>> index_to_substate(0)
200
+ 'a'
201
+ >>> index_to_substate(26)
202
+ 'aa'
203
+ >>> index_to_substate(27)
204
+ 'bb'
205
+ >>> index_to_substate(194)
206
+ 'mmmmmmmm'
207
+ used in bitvec_to_substates
208
+ '''
209
+ number = index + 1 # because python indices start at 0
210
+ letter_dict = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e', 6:'f', 7:'g', 8:'h', 9:'i', 10:'j',
211
+ 11:'k', 12:'l', 13:'m', 14:'n', 15:'o', 16:'p', 17:'q', 18:'r', 19:'s', 20:'t',
212
+ 21:'u', 22:'v', 23:'w', 24:'x', 25:'y', 26:'z'} # could be make less hard-code-y
213
+ # but this makes it clearer and more intuitive what we want to happen
214
+ letter = letter_dict[number%26]
215
+ return ((number//26) + 1) * letter
216
+
217
+ def int_to_binary(integer, number, backwards_binary_str = ''):
218
+ '''converts a #x string to a #b string. follows the first algorithm that shows up on google
219
+ when you google how to do this
220
+ used in bitvec_to_substates'''
221
+ rem = integer%2
222
+ new_backwards_str = backwards_binary_str + str(rem)
223
+ if integer//2 == 0: # base case: we've reached the end
224
+ remaining_0s_to_tack_on = number - len(new_backwards_str) # to fill in the zeroes
225
+ return '#b' + remaining_0s_to_tack_on * '0' + new_backwards_str[::-1]
226
+ new_int = integer//2
227
+ return int_to_binary(new_int, number, new_backwards_str)
228
+
229
+
230
+ # TODO: linter says all or none of the returns should be an expression
231
+ def bitvec_to_substates(bit_vec, N):
232
+ '''converts bitvectors to fusions of atomic states.'''
233
+ bit_vec_as_string = bit_vec.sexpr()
234
+ if 'x' in bit_vec_as_string: # if we have a hexadecimal, ie N=4m
235
+ integer = int(bit_vec_as_string[2:],16)
236
+ bit_vec_as_string = int_to_binary(integer, N)
237
+ bit_vec_backwards = bit_vec_as_string[::-1]
238
+ state_repr = ""
239
+ for i, char in enumerate(bit_vec_backwards):
240
+ if char == "b":
241
+ if not state_repr:
242
+ return "□" # null state
243
+ return state_repr[0 : len(state_repr) - 1]
244
+ if char == "1":
245
+ state_repr += index_to_substate(i)
246
+ state_repr += "."
247
+
248
+ def infix_combine(prem,con):
249
+ '''combines the premises with the negation of the conclusion(s).
250
+ premises are infix sentences, and so are the conclusions
251
+ imported by model_structure'''
252
+ # if prem is None:
253
+ # prem = []
254
+ input_sent = prem
255
+ for sent in con:
256
+ neg_sent = '\\neg ' + sent
257
+ input_sent.append(neg_sent)
258
+ return input_sent