Implementing an efficient 2-SAT solving algorithm - python-3.x

I was reading about the 2-SAT problem on Wikipedia and I was wondering what the O(n) algorithm looks like in Python.
So far I've only found implementations that either are in other programming languages or that just determine whether an expression has solutions or not, without given the solution itself.
How could the O(n) algorithm for finding the values of variables be written in Python?

Here is an OOP implementation in Python:
import re
class TwoSat:
class Variable:
def __init__(self, name, negated=None):
self.name = name
self.negated = negated or TwoSat.Variable("~" + name, self)
self.implies = set()
self.impliedby = set()
self.component = -1
def disjunction(self, b):
self.negated.implication(b)
b.negated.implication(self)
def implication(self, b):
self.implies.add(b)
b.impliedby.add(self)
def postorder(self, visited):
if self not in visited:
visited.add(self)
for neighbor in self.implies:
yield from neighbor.postorder(visited)
yield self
def setcomponent(self, component):
if self.component == -1:
self.component = component
for neighbor in self.impliedby:
neighbor.setcomponent(component)
def value(self):
diff = self.component - self.negated.component
return diff > 0 if diff else None
### end of class Variable
def __init__(self, s):
self.variables = {}
for a_neg, a_name, b_neg, b_name in re.findall(r"(~)?(\w+).*?(~)?(\w+)", s):
self.getvariable(a_neg, a_name).disjunction(self.getvariable(b_neg, b_name))
def getvariable(self, neg, name):
if name not in self.variables:
self.variables[name] = TwoSat.Variable(name)
self.variables["~" + name] = self.variables[name].negated
a = self.variables[name]
return a.negated if neg else a
def postorder(self):
visited = set()
for startvariable in self.variables.values():
yield from startvariable.postorder(visited)
def setcomponents(self):
for i, variable in enumerate(reversed(list(self.postorder()))):
variable.setcomponent(i)
def issolved(self):
return all(variable.value() is not None for variable in self.variables.values())
def solve(self):
self.setcomponents()
return self.issolved()
def truevariables(self):
if self.issolved():
return [variable.name for variable in self.variables.values() if variable.value()]
def __repr__(self):
return " ∧ ".join(
f"({a.name} → {b.name})"
for a in self.variables.values()
for b in a.implies
)
Here is an example of how this class can be used:
problem = TwoSat("(~a+~b)*(b+~c)*(c+g)*(d+a)*(~f+i)*(~i+~j)*(~h+d)*(~d+~b)*(~f+c)*(h+~i)*(i+~g)")
print(problem)
problem.solve()
print("solution: ", problem.truevariables())
The TwoSat constructor takes one argument, a string, which should provide the conjugation of disjunction pairs. The syntax rules for this string are:
literals must use alphanumeric characters (underscores allowed), representing a variable, optionally prefixed with a ~ to denote negation.
All other characters are just taken as separators and are not validated.
All literals are taken in pairs and each consecutive pair is assumed to form a disjunction clause.
If the number of literals is odd, then although that expression is not a valid 2SAT expression, the last literal is simply ignored.
So the above example could also have taken this string representing the same problem:
problem = TwoSat("~a ~b b ~c c g d a ~f i ~i ~j ~h d ~d ~b ~f c h ~i i ~g")
Alternatively, you can use the getvariable and disjunction methods to build the expression. Look at the __init__ method how the constructor uses those methods when parsing the string. For example:
problem = TwoSat()
for variable in "abcdefghij":
problem.getvariable(False, variable)
# Define the disjunction ~a + ~b:
problem.variables["a"].negated.disjunction(problem.variables["b"].negated)
# ...etc
The algorithm is the one explained in the 2-satisiability article on Wikipedia, identifying strongly connected components using Kosaraju's algorithm

Related

Count number of basic instruction and their type

I have some code (few hundreds of lines) and i would like to reproduce the code on some "real" controller.
I would like to predict how long the code would take to run by counting how many instructions (basic arithmetic, type of operation (floating point, binary, etc..)
And i wonder if it is possible to do on python (if yes how so ? haven't found anything yet)
I know there is a time feature to measure how long it takes to run the code but the calculation power of my PC and the controller i plan to use are not the same.
Also i tried counting it myself but it is quite a pain and subject to errors
Ideal result would be like:
X number of basic arithmetic operation using INT
Y number of basic arithmetic operation using FLOAT
Z binary operation
etc ...
Thank you
Your question got me thinking. I wrote a little framework for how you might implement something like this. Basically you create your own number class and a collection to hold them all. Then you over-ride the default operators and increment a variable every time you enter those functions. Note that this is NOT robust.. There's no error checking and it assumes that all operations are done with the custom class objects.
from collections import defaultdict # Acts like a dictionary, but every time you add a key, the value defaults to a specified value
class Collection(object): # Use this to hold your custom types
def __init__(self):
self.items = []
return
def add_item(self, item):
self.items.append(item)
class myFloat(object): # Your custom float class
def __init__(self, val, collection):
""" val is the value, collection is the Collections object where we will place your object """
self.val = float(val)
self.op_counts = defaultdict(int) # a dictionary where values default to an integer, 0.
collection.add_item(self) # Add this object to the collection
def __add__(self, other): # Called when you use + on two myFloat
self.op_counts["+"] += 1 # Adds 1 to the number of "+" used
return self.val + other.val # returns the result.
def __sub__(self, other): # Called when you use - on two myFloat
self.op_counts["-"] += 1
return self.val - other.val
def __mul__(self, other): # Called when you use * on two myFloat
self.op_counts["*"] += 1
return self.val * other.val
def __truediv__(self, other): # Called when you use / on two myFloat
self.op_counts["/"] += 1
return self.val / other.val
### EXAMPLE
import random
ops = ["+", "-", "*", "/"]
# We should create a separate Collection object for each custom type we have.
# Since we only have myFloat, we make one Collection object to hold the myFloats.
float_collection = Collection()
# This instantiates a myFloat object with val=7.12 and uses your float_collection
y = myFloat(7.12, float_collection)
for x in range(1, 1000):
op = random.choice(ops) # Pick a random operation
xx = myFloat(x, float_collection) # Instantiate another myFloat
# Now perform the operation on xx and y. eval evaluates the string but
# opens the door for security holes if you are worried about hackers. CAREFUL.
eval(f"y{op}xx") # Remove this line and use the one below if your python < 3.6
# eval("y{}xx".format(op))
print("### RESULTS ###")
result_op_counts = defaultdict(int) # We use this to count up our results
# Sorry for the confusing syntax. The items parameter of the Collection object
# is NOT the same as the items() method for dictionaries.
# float_collection.items is a list of your myFloats.
# the items() method for dictionary returns a dict_items object that you can iterate through.
# This loop tallies up all the results
for myFloatObj in float_collection.items:
for op, ct in myFloatObj.op_counts.items():
result_op_counts[op] += ct
# And this loop prints them.
for k,v in result_op_counts.items():
print(f"{k}: {v} operations") # Remove this line and use the one below if your python < 3.6
# print("{}: {} operations".format(k, v))
This outputs
### RESULTS ###
*: 227 operations
/: 247 operations
+: 275 operations
-: 250 operations

How to define external overloading for PriorityQueue to manage heterogeneous type elements?

I want to store pairs (prio,val) of heterogeneous types in a python PriorityQueue. Here val can be either a string or a custom class object.
When prio are equals, the PriorityQueue (actually heapq) implementation comes to compare the second member, thus comparing a string and a custom objects.
Depending on the order the elements were stored, it comes to compare either:
custom_object < string
string < custom_object
Case 1. translates to custom_object.__lt__(string) and this is fine, as i can overload the def __lt__:method in my custom class.
Case 2. : i am stuck because i do not know how to redefine __lt__ for strings.
Below is a MWE that inserts 3 elements with equal priorities (the value 1).
Running it results in the error message:
TypeError: '<' not supported between instances of 'str' and 'C'
import queue
class C:
def __init__(self,value):
__value__ = value
def __lt__(selfself,other):
return 0
q = queue.PriorityQueue()
tuple1=(1,"t1")
tuple2=(1,C("t2"))
tuple3=(1,"t3")
q.put(tuple1)
q.put(tuple2)
q.put(tuple3)
print( q.get())
If a does not supply an implementation for a < b, then Python will look for an implementation of b > a next.
class C:
def __lt__(self, other):
return 0
def __gt__(self, other):
return 1
c = C()
print(c < 'a') # 0
print('a' < c) # 1

Python 3: best way to implement your own type with constraints

I'm doing a Python 3 based data conversion and certain character based fields I operate on have specific character allowances and length constraints applied to them.
I'd want to have some sort of swappable/configurable constraint function I roll myself that I could call.
Can you extend str?
Is it best to define a class for this and make variables implementations of that class.
Or are there simpler ways to do this with Python 3?
I'm wondering if anyone can give me pointers as to what to Google for inspiration?
(My initial thoughts are to look at SQLAlchemy's internal code for inspiration for things like Column).
EDIT: SQLAlchemy's code is too sophisticated for this scenario!
For example a type that only allows:
alphanumerics (upper+lowercase)
numerics
plus a selection of special characters.
This may vary by field, but some may use same function.
Hence desire to create custom re-usable types.
I'll do character stripping or substitution.
Then one may only allow 50 chars, whilst another may allow 500 etc.
I'll pass back a tuple with original value, converted value, a boolean to indicate truncation occurred
This is what I ended up with:
valobj.py
import utils
class UDT:
def __init__(self, converter, maxlen, value):
if utils.getClassName(converter) != 'function':
raise TypeError(f'converter {converter} is not a function')
if int(maxlen) <= 0:
raise TypeError(f'maxlen {maxlen} must be 1 or more')
if utils.getClassName(value) != 'str':
raise TypeError(f'value {value} is not a Python String')
self.converter = converter
self.maxlen = int(maxlen)
self.value = value
def convert(self):
intermed = self.converter(self.value)
truncated = len(intermed) > self.maxlen
result = intermed[:self.maxlen] if truncated else intermed
return (result, truncated, self.value)
class Job:
def __init__(self, name):
self._name_tuple = UDT(utils.fix_chars, 64, name).convert()
utils.py
import string
def getClassName(arg):
return(str(type(arg)).replace("<class '","").replace("'>",""))
def fix_chars(text) -> str:
result = ''
for c in text:
if ( (string.ascii_letters.find(c) != -1)
or (string.digits.find(c) != -1)
or ('._-#'.find(c) != -1)
):
result += c
else:
result += '_'
result = tidy_up_str(result)
return (result)
def tidy_up_str(text) -> str:
result = text
result = result.replace('_-_', '_')
while result.find('__') != -1:
result = result.replace('__', '_')
if result.endswith('_'):
result = result[:-1]
return result

Python3: why the comparison is naturally made?

In the code below, I defined '<' in the magic method __lt__(), which will return True if the first argument is less than the second one, return False otherwise.
from functools import total_ordering
#total_ordering
class Currency:
"""
One object of class Currency stores one amount of money, dollars and cents.
"""
def __add__(self, other):
"""
returns the result of adding self to other
"""
total = Currency(self.dollars, self.cents)
total.dollars = total.dollars + other.dollars
print (other.dollars)
total.cents = total.cents + other.cents
print (other.cents)
if total.cents > 100:
total.cents = total.cents - 100
total.dollars = total.dollars +1
return total
def __init__(self, dollars=0, cents=0):
self.dollars = dollars
self.cents = cents
def __str__(self):
return "$"+str(self.dollars)+"."+str(self.cents)
def __eq__(self, other):
return self.dollars==other.dollars and self.cents==other.cents
def __lt__(self, other):
if self.dollars<other.dollars:
return True
elif self.dollars > other.dollars:
return False
else: # dollars are equal
return self.cents < other.cents
And then I called __lt__() in the test program with '<'. In this case, the candyPrice(first argument) is less than bookPrice(second argument), so it returned True as expected. And then, I compared these two values with '>' which was not predefined in class Currency, but it also returned False as expected. So I'm wondering if it's because __lt__() was defined already, then the opposite expression, the '>' expression, was also implicitly defined?
if __name__ == "__main__":
candyPrice = Currency (1, 17) # $1.17
bookPrice = Currency (12, 99) # $12.99
print (candyPrice < bookPrice)
print (candyPrice > bookPrice)
You used the #total_ordering class decorator. This decorator explicitly adds the other methods for you.
From the #functools.total_ordering documentation:
Given a class defining one or more rich comparison ordering methods, this class decorator supplies the rest. This simplifies the effort involved in specifying all of the possible rich comparison operations:
The class must define one of __lt__(), __le__(), __gt__(), or __ge__(). In addition, the class should supply an __eq__() method.
So even though you did not define a __gt__ method, the class decorator has defined one for you using your __lt__ method, together with __eq__.
For example, when defining a __lt__ method, the __gt__() implementation is set to:
def _gt_from_lt(self, other, NotImplemented=NotImplemented):
'Return a > b. Computed by #total_ordering from (not a < b) and (a != b).'
op_result = self.__lt__(other)
if op_result is NotImplemented:
return op_result
return not op_result and self != other
So if self < other is false, self != other is used. You did not define a __ne__ method, but you did provide a __eq__ and the default for __ne__ is then to return not self.__eq__(other); see the object.__ne__() documentation:
By default, __ne__() delegates to __eq__() and inverts the result unless it is NotImplemented.
For your test Currency instances __eq__ is not needed, candyPrice.__gt__(bookPrice) calls candyPrice.__lt__(bookPrice), which returns true and thus False is returned without checking for self != other.

Why are changes to a list, in an instance of a python 3 class, global?

Why when I create a class with a list, the list and its contents become global
class A:
my_list = []
string = ""
def add(self, data):
self.string += "a"
self.my_list.append(data)
def print_list(self):
print(self.string)
print(self.my_list)
a = A()
b = A()
a.add("test")
a.print_list()
b.print_list()
Both a and b will print the list that was created by a.add
# results of a.print_list
xa
['test']
# results of b.print_list
x
['test']
So my question is, is this normal for python3, or a bug.
Doesnt seem right to me that only the list is modified globally.
This is the explaining:
Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages. This is usually not appreciated on a first glance at Python, and can be safely ignored when dealing with immutable basic types (numbers, strings, tuples). However, aliasing has a possibly surprising effect on the semantics of Python code involving mutable objects such as lists, dictionaries, and most other types. This is usually used to the benefit of the program, since aliases behave like pointers in some respects. For example, passing an object is cheap since only a pointer is passed by the implementation; and if a function modifies an object passed as an argument, the caller will see the change — this eliminates the need for two different argument passing mechanisms as in Pascal.
From oficial Python 3 docs
And this is the solution:
(...) use an instance variable instead (...)
Like this:
class Dog:
def __init__(self, name):
self.name = name
self.tricks = [] # creates a new empty list for each dog
def add_trick(self, trick):
self.tricks.append(trick)
Result of above code:
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks ['roll over']
>>> e.tricks ['play dead']
In your example, you should move your my_list = [] declaration to the init function...
class A:
string = ""
def __init__(self):
self.my_list = []
def add(self, data):
self.string += "a"
self.my_list.append(data)
def print_list(self):
print(self.string)
print(self.my_list)
a = A()
b = A()
a.add("test")
a.print_list()
b.print_list()
Hope this help.
Regards
Strings are immutable so
self.string += "a"
creates a new object and binds it to self.string
This is clearly mutating the list in place
self.my_list.append(data)
Perhaps more interesting is that
self.my_list += [data]
also mutates the list
The general rule is that __iadd__ does behave differently for mutable vs immutable objects

Resources