Multiply.py
Multiply.py

#   Multiply.py
#
#   Non-Deterministic Processor (NDP) - efficient parallel SAT-solver
#   Copyright (c) 2023 GridSAT Stiftung
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
#   GridSAT Stiftung - Georgstr. 11 - 30159 Hannover - Germany - ipfs: gridsat.eth/ - info@gridsat.io
#

from Clause import Clause
from Set import Set

class Multiply:
    def __init__(self) -> None:
        pass

    # This preprocessing method is ONLY for multiplication CNFs generated by Paul Purdom and Amr Sabry at https://cgi.luddy.indiana.edu/~sabry/cnf.html
    # The task multiplies two numbers using the input CNF. It is irrelevant if the CNF was generated for a specific number of bit-length n.
    # What matters is that we can use the CNF as a processor to multiply two numbers and produce a number x of length n
    
    def preprocess_set(selfcnfSetfact1fact2):
        # compatibility check
        if not (cnf and len(cnf.clausesand len(cnf.clauses[0].raw) == 3):
            print("The input set is not in Purdom-Sabry format. Multiplication feature skipped.")
            return False

        vars_map = {}

        ### evaluate the two input factors/multipliers
        # first get the size of each factor
        # length of factor1 and factor 2 are in first clause
        cnf.fact1_len = cnf.clauses[0].raw[1]-1
        cnf.fact2_len = abs(cnf.clauses[0].raw[2]) - cnf.clauses[0].raw[1]

        # get fact1 var to have the bigger value
        if fact2 > fact1:
            fact1fact2 = fact2fact1
        
        # check if input factors are bigger than the factors' bits in the CNF
        fact1bin = bin(fact1)[2:].rjust(cnf.fact1_len'0')[::-1]
        fact2bin = bin(fact2)[2:].rjust(cnf.fact2_len'0')[::-1]
        if len(fact1bin) > cnf.fact1_len or len(fact2bin) > cnf.fact2_len:
            print("The tree is not compatible. One or both factors are greater than factors assigned bits in the tree.")
            return False

        vars_map = {}
        i = 1
        for factbinflen in [(fact1bincnf.fact1_len), (fact2bincnf.fact2_len)]:
            for bit in factbin:
                vars_map[i] = bool(int(bit))
                i += 1

        # The size of the output number in bits equal number of unit clauses
        result_bits = []
        for i in range(len(cnf.clauses) - 1, -1, -1):
            cl = cnf.clauses[i]
            if len(cl.raw) == 1:
                result_bits.append(abs(cl.raw[0]))

                # remove unit clauses to make the CNF be a general CNF for all results within the N-bit range
                cnf.clauses.pop(i)

        cnf.multiply_result_bits = result_bits[::-1]
        cnf.evaluated_vars = vars_map

        cnf.substitute_vars(vars_map)
        
        return True