How can I convert an IntVector to an Int in z3py - python

I am using z3py and I have an IntVector of size 3. I need to parse each digit in the IntVector as one whole number. Meaning, if I have an IntVector which has constraints like this:
myIntVector = IntVector('iv', 3)
s = Solver()
s.add(iv[0] == 5)
s.add(iv[1] == 2)
s.add(iv[2] == 6)
….
I need to be able to operate on the number 526 as an Int sort in z3 because I need to both add constraints that apply to each individual member of the IntVector (digit) AND constraints which apply to the whole number, in this case 526. I cannot do something like:
s.add(iv[0] / iv == 55)
because those are 2 separate types. iv[0] is an Int while iv is an IntVector

Here is an example that uses the concept of IntVector as separate digits and as numbers formed by these digits.
It solves the traditional riddle to replace each of the letters of "SEND + MORE = MONEY" to a different digit.
from z3 import *
# trying to find different digits for each letter for SEND+MORE=MONEY
letters = 'SENDMOREMONEY'
iv = IntVector('iv', len(letters))
send = Int('send')
more = Int('more')
money = Int('money')
s = Solver()
# all letters to be replaced by digits 0..9
s.add([And(i >= 0, i <= 9) for i in iv])
# the first digit of a number can not be 0
s.add(And(iv[0] > 0, iv[4] > 0, iv[8] > 0))
# distinct letters need distinct digits
s.add(Distinct([i for k, i in enumerate(iv) if letters[k] not in letters[:k]]))
# "send" is the number formed by the first 4 digits, "more" the 4 next, "money" the last
s.add(send == Sum([10**(3-k)*i for k,i in enumerate(iv[:4])]))
s.add(more == Sum([10**(3-k)*i for k,i in enumerate(iv[4:8])]))
s.add(money == Sum([10**(4-k)*i for k,i in enumerate(iv[8:])]))
# the numbers for "send" and "more" sum together to "money"
s.add(send + more == money)
if s.check() == sat:
m = s.model()
# list each digit of iv
print([m[i].as_long() for i in iv])
# show the sum as "send" + "more" = "money"
print("{} + {} = {}".format(m[send].as_long(), m[more].as_long(), m[money].as_long()))

Related

sum of every other digit and doubling the rest

I'm working on a card number check code, for now I created a function that asks for the card number and checks if it is 8 digits or not (it has to be 8) and then calls another function that will do the math and check if the card is valid. For this function:
Starting from the rightmost digit, form the sum of every other digit. For example, if the card number is 1234 5678, then you form the sum 8 + 6 + 4 + 2 = 20
Double each of the digits that were not included in the preview step and then add all digits of the resulting numbers. For example, the digits that were not included are 7 5 3 1, we double the, 14 10 6 2, and then we sum each digit, 1 + 4 + 1 + 0 + 6 + 2 = 14
Add the sums of the two steps, 20 + 14 = 34, if the last digit is 0 then the card is valid, otherwise it is not valid (which is our case)
My problem is that I don't know how to iterate and get the sum of every other digit or double the other number which were not included in step 2. My thought was to use a while loop but then what?
EDIT: since some answers used lists... we didn't study lists yet, so I should not use it, we are only allowed to use sample stuff, loops, functions, etc.. even sum(map()) we didn't study
That is my code for now (its not much but just thought put it anyway)
def getCard():
CardInput = int(input("Enter your 8 digit credit card number: "))
if len(CardInput) == 8:
CardCheck(CardInput)
else:
print("Invalid Input: Should be exactly 8 digits!")
getCard()
def CardCheck(CardNumber):
Position = 0
Sum = 0
DoubleSum = 0
FinalSum = 0
while CardNumber >= 0:
Position += 1
So, the ugly way of doing is, you can write a for loop and use indexing for access specific elements
for i in range(len(CardInput)):
# it will iterate from 0 to 7
print(CardInput[i]) # here you get ith element
if i % 2 == 1:
print("I am other!") # you can sum your things here into another variable
Or with while:
while position < len(CardInput):
print(CardInput[position])
position += 1
It assumes CardInput is str, so I recommend to not convert it earlier.
However pythonic way would be
sum(map(int, CardInput[1::2])))
CardInput[1::2] returns list of every second element starting from second (0 is first).
map converts every element to in.
sum sums elements.
prompt = "Enter the eight-digit number: "
while True:
number = input(prompt)
if len(number) == 8 and number.isdigit():
break
prompt = "Oops, try again: "
first_digits = number[1::2] # If the user entered '12345678', this will be the substring '2468'
first_sum = sum(map(int, first_digits)) # Take each digit (character), map it to a single-digit integer, and take the sum of all single-digit integers
second_digits = number[0::2] # If the user entered '12345678', this will be the substring '1357'
doubled_ints = [int(char) * 2 for char in second_digits] # Take each digit (character), turn it into an integer, double it, and put it in a list.
second_sum = sum(map(int, "".join(map(str, doubled_ints)))) # Merge all integers in 'doubled_ints' into a single string, take each character, map it to a single digit integer, and take the sum of all integers.
total_sum = first_sum + second_sum
total_sum_last_digit = str(total_sum)[-1]
is_valid_card = (total_sum_last_digit == '0')
if is_valid_card:
print("Your card is valid (total sum: {})".format(total_sum))
else:
print("Your card is NOT valid (total sum: {})".format(total_sum))
def getCard():
CardInput = input("Enter your 8 digit credit card number: ")
if len(CardInput) == 8:
CardCheck(CardInput)
else:
print("Invalid Input: Should be exactly 8 digits!")
getCard()
def CardCheck(CardNumber):
list_CardNumber = [x for x in "25424334"]
Sum = sum(int(x) for x in list_CardNumber[1:8:-2])
DoubleSum = 2*sum(int(x) for x in list_CardNumber[0:8:-2])
FinalSum = Sum + DoubleSum
if str(FinalSum)[-1] == "0":
print("Valid Input")
else:
print("Invalid Input")
To get you started, you should check out enumerate(), it'll simplify things if you're just going to use loops by giving you easy access to both the index and value every loop.
step1 = 0
for i, x in enumerate(number):
if i % 2:
print('index: '+ str(i), 'value: '+ x)
step1 += int(x)
print('step 1: ', step1)
Output:
index: 1 value: 2
index: 3 value: 4
index: 5 value: 6
index: 7 value: 8
step 1: 20
You can use:
# lets say
CardNumber = '12345678'
# as mentioned by kosciej16
# get every other digit starting from the second one
# convert them to integers and sum
part1 = sum(map(int, CardNumber[1::2]))
# get every other digit starting from the first one
# convert them to integers and double them
# join all the digits into a string then sum all the digits
part2 = sum(map(int,''.join(list(map(lambda x: str(int(x)*2), CardNumber[0::2])))))
result = part1 + part2
print(result)
Output:
34
Edit:
Only with loops you can use:
# lets say
CardNumber = '12345678'
total_sum = 0
for idx, digit in enumerate(CardNumber):
if idx % 2 == 1:
total_sum += int(digit)
else:
number = str(int(digit)*2)
for d in number:
total_sum += int(d)
print(total_sum)
output:
34
Since you need to iterate over the digits, it's actually easier IMO if you leave it as a string, rather than converting the input to an int; that way you can just iterate over the digits and convert them to int individuall to do math on them.
Given an 8-digit long string card, it might look like this, broken into steps:
even_sum = sum(int(n) for n in card[1::2])
double_odds = (2 * int(n) for n in card[0::2])
double_odd_sum = sum(int(c) for do in double_odds for c in str(do))
All together with some logic to loop while the input is invalid:
def get_card() -> str:
"""Returns a valid card number, or raises ValueError."""
card = input("Enter your 8 digit credit card number: ")
if len(card) != 8 or not card.isdecimal():
raise ValueError("Invalid input: Should be exactly 8 digits!")
card_check(card)
return card
def card_check(card: str) -> None:
"""Raises ValueError if card checksum fails, otherwise returns None."""
even_sum = sum(int(n) for n in card[1::2])
double_odds = (2 * int(n) for n in card[::2])
double_odd_sum = sum(int(c) for do in double_odds for c in str(do))
if (even_sum + double_odd_sum) % 10:
raise ValueError("Card checksum failed!")
while True:
try:
print(f"{get_card()} is a valid card number!")
except ValueError as e:
print(e)

Python beginner - RGB values to HEX. How bad is my code?

I recently wrote a program that calculates the hex value when given rgb values. I was just wondering if my code is terrible (i did my best to write it from scratch without much help). I'm still a beginner and trying to learn.
Any help would be greatly appreciated (guidance about how i could do things better etc.).
Thank you
# sets the HEX letters for numbers above 9
hex_table = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8, '9':9,
'a':10, 'b':11, 'c':12, 'd':13, 'e':14, 'f':15}
# creates variable for the keys in dictionary
key_list = list(hex_table.keys())
# creates variable for values in dictionary
val_list = list(hex_table.values())
def test(r= int(input('red value: ')),g= int(input('green value: ')), b= int(input('blue value: '))):
# finds the index of the value
red_value = r // 16
green_value = g // 16
blue_value = b // 16
# Calcuate the remainder
red_float = float(r) / 16
red_remainder = red_float % 1
green_float = float(g) / 16
green_remainder = green_float % 1
blue_float = float(b) / 16
blue_remainder = blue_float % 1
# adds '#' in front of the result
print('#',end='')
#find the first two values in HEX code
if r >= 10:
print(key_list[val_list.index(red_value)],end='')
second_letter = (int(red_remainder * 16))
print(key_list[val_list.index(second_letter)],end='')
elif r <10:
print(red_value,end='')
print(int(red_remainder * 16),end='')
#find the next two values
if g >= 10:
print(key_list[val_list.index(green_value)],end='')
second_letter = (int(green_remainder * 16))
print(key_list[val_list.index(second_letter)],end='')
elif g <10:
print(green_value,end='')
print(int(green_remainder * 16),end='')
#find the last two values
if b >= 10:
print(key_list[val_list.index(blue_value)],end='')
second_letter = (int(blue_remainder * 16))
print(key_list[val_list.index(second_letter)],end='')
elif b <10:
print(blue_value,end='')
print(int(blue_remainder * 16),end='')
test()
You could reduce the amount of code by a lot by reducing the amount of times you repeat yourself, you are calculating the values for the digits for all three colours in the same function, therefore repeating yourself 3 times.
I've wrote my answer using JavaScript but I will explain what I am doing.
function getDigit(val) {
var alphabet = ["a", "b", "c", "d", "e", "f"]
if (val >= 10 && val < 16)
val = alphabet[val - 10];
return val.toString();
}
function helper(val) {
var first = Math.floor(val / 16)
var second = val % 16;
return getDigit(first) + getDigit(second)
}
function rgbToHex(red, green, blue) {
return helper(red) + helper(green) + helper(blue);
}
I have created two functions to help calculate the digits for each of the RGB values.
The helper() function calculates two numbers for the first and second digits. Lets use 24 and 172 as an example.
To find the first digit, you can divide the value by 16, and Floor the answer so it rounds down to a single digit.
24 / 16 = 1.5, Floor(1.5) = 1;
Therefore are first digit is 1.
And for the second digit we take the remainder of the value divided by 16.
24 % 16 = 8
So the full value for would be 18
Lets see 172 now.
172 / 16 = 10.75, Floor(10.75) = 10;
This will not work because the value should be "a" rather than "10", this is where the getDigit() function comes in, this function will take the value and check if it is between 10 and 15. We then take 10 from the value to find which letter we should use from the 'alphabet' array.
So for 10, we get 10 - 10 = 0; which means we will use the value at index 0 which gives us "a"
We can do the same for the second digit
172 % 16 = 12; Now the getDigit() function is called again.
12 - 10 = 2; so we take the item from index 2 in the array, which is "c"
so for 172 the value will be ac
Here's my slightly amended code:
hex_table = {'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,
'A':10, 'B':11, 'C':12, 'D':13, 'E':14, 'F':15}
key_list = list(hex_table.keys())
val_list = list(hex_table.values())
def rgb(num_val):
num = num_val // 16
num_float = float(num_val) / 16
num_remainder = num_float % 1
if num_val >= 10:
print(key_list[val_list.index(num)], end='')
second_letter = (int(num_remainder * 16))
print(key_list[val_list.index(second_letter)],end='')
elif num_val <10:
print(num_val)
print(int(num_remainder * 16))
def rgb_hex(r,g,b):
print('#',end='')
return (f'{rgb(r)} {rgb(g)} {rgb(b)}')
rgb_hex(220,20,60)
This is an old question but for information, I developed a package with some utilities related to colors and colormaps and contains the rgb2hex function you were looking to convert triplet into hexa value (which can be found in many other packages, e.g. matplotlib). It's on pypi
pip install colormap
and then
>>> from colormap import rgb2hex
>>> rgb2hex(0, 128, 64)
'##008040'
Validity of the inputs is checked (values must be between 0 and 255).

When given a letter sequence , find closest from given list

I am writing a cable mapping script that needs to find the closest switch. So if a patch panel is in Rack 08AB, and there is a switch in Rack 08AC and 08AD, I need it to pick the closest(08AC). The problem is the rack numbering sequence. The first two digits will always be the same (08) and the letters increment. But they increment A-Z then AA-AZ. So if the panel is in Rack 08Z, 08AA is closer than 08X.
I have this working by converting the letters into numbers and seeing which is closest but it seems clunky and I'm wondering if there's a better way:
###CLOSEST SWITCH IS IN 08AA
full_panel_location = '08Z'
full_switches_location = ['08X', '08AA']
switches_checksum = []
###REMOVE DIGITS AND CONVERT LETTERS TO CHECKSUM
panel_letters = ''.join([i for i in full_panel_location if not i.isdigit()])
panel_checksum = int(reduce(lambda x,y:x+y, map(ord, panel_letters)))
if panel_checksum > 100:
panel_checksum -= 39
for switch in full_switches_location:
switch_letters = ''.join([i for i in switch if not i.isdigit()])
switch_checksum = int(reduce(lambda x,y:x+y, map(ord, switch_letters)))
if switch_checksum > 100:
switch_checksum -= 39
switches_checksum.append(switch_checksum)
###FIND CLOSEST CHECKSUM/INDEX/SWITCH
closest_switch_checksum = min(switches_checksum, key=lambda x: abs(x - panel_checksum))
closest_switch_index = switches_checksum.index(closest_switch_checksum)
closest_switch = full_switches_location[closest_switch_index]
This provides the closest switch being 08AA, which is what I want. My question is, is there a better way to be doing this?
This is basically a base 26 conversion problem. Iterate through each letter of a location in reversed order and add its ordinal number difference to letter A times 26 to the power of the letter offset to get the checksum, with which you can calculate the distance to the reference location as a key for the min function:
def checksum(x):
s = 0
for i, c in enumerate(reversed(x)):
s += (ord(c) - ord('A') + 1) * 26 ** i
return s
full_panel_location = '08Z'
full_switches_location = ['08X', '08AA']
panel_checksum = checksum(full_panel_location[2:])
print(min(full_switches_location, key=lambda i: abs(checksum(i[2:]) - panel_checksum)))
This outputs:
08AA

Solving Python Riddle

Problem I am supposed to solve:
The Riddler is planning his next caper somewhere on
Pennsylvania Avenue. The address on Pennsylvania is a four-digit number with
the following properties.
All four digits are different,
The digit in the thousands place is three times the digit in the tens place,
The number is odd, and
The sum of the digits is 27.
So I made a for loop that checks each four digit integer and puts the value in a place holder (i.e. thousands, hundreds, etc.) And conditional if statements to fit the conditions. But my problem is that the IDE gives me no error when I run the code, but it does not print my statement at the end. I'm having trouble figuring out what is wrong with my code.
address = 0
thousand = 0
hundred = 0
ten = 0
one = 0
for address in range(1000,9999+1):
thousand = (address/1000)%10
hundred = (address/100)%10
ten = (address/10)%10
one = (address%10)
if (thousand != hundred) and (thousand != ten) and (thousand != one) and (hundred != ten) and (hundred != one) and (ten !=one):
if thousand == (3*ten):
if one % 2 != 0:
if thousand+hundred+ten+one == 27:
print("The address is: ",address, "Pennsylvania Ave.")
It runs but the print statement does not show up.
All four digits are different, The digit in the thousands place is three times the digit in the tens place, The number is odd, and The sum of the digits is 27.
The digit in the thousands place is three times the digit in the tens place: valid combos are 3x1x, 6x2x, 9x3x.
The sum of the digits is 27: only 9x3x is possible since 27 - (6 + 2) > 8+7, the maximum remaining digits. In fact 27 - (9 + 3) = 15. The remaining digits can be 9,6 or 8,7
All four digits are different: 9,5 is not an option. The number is either 9837 or 9738.
The number is odd: it's 9837.
Some pencil and paper works better than a for loop here.
That being said, keep in mind that / is the true division operator in Python 3, irrespective of type. So when address = 6754, for example
thousand = (address / 1000) % 10
evaluates as
thousand = 6.754 % 10
which is just 6.754, not 6 as you were probably hoping. To get 6, use the integer division operator //:
thousand = (address // 1000) % 10
Number Theory
isop = []
for a in range(1, 10, 1):
for b in range(0, 10, 1):
for c in range(0, 10, 1):
for d in range(0, 10, 1):
if a!=b and a!=c and a!=d and b!=c and b!=d and c!=d:
sum = a+b+c+d
if a==3*c and sum == 27:
num = a*1000 + b*100 + c*10 + d
if num % 2 == 1:
isop.append(num)
for i in range(len(isop)):
print(isop[i])

Add numbers in hexadecimal base without converting bases?

I need to write a function which gets two numbers in hexadecimal base, and calculates the sum of both of them, I'm not allowed to convert them to decimal base, the code is supposed to calculate it "manually" using loops.
for example this is how it should work:
1
1 f 5 (A)
+ 5 a (B)
-------------
= 2 4 f
Here is an input example:
>>> add("a5", "17")
'bc'
I've started building my code but I got stuck, I thought I would divide into three ifs, one that would sum up only numbers, other sums numbers and letters, and the third one sums letters, but I don't know how to continue from here:
def add_hex(A,B):
lstA = [int(l) for l in str(A)]
lstB = [int(l) for l in str(B)]
if len(A)>len(B):
A=B
B=A
A='0'*(len(B)-len(A))+A
remainder=False
result=''
for i in range(len(B)-1)
if (A[i]>0 and A[i]<10) and (B[i]>0 and B[i]<10):
A[i]+B[i]=result
if A[i]+B[i]>10:
result+='1'
Any help is greatly appreciated, I have no clue how to start on this!
You can have a sub-function that adds two single-digit hex numbers and returns their single-digit sum and a carry (either 0 or 1). This function will take three inputs: two numbers you want to add and a carry-in. You can then loop through the digits of the two numbers you want to add from least significant to most significant, and apply this function for every pair of digits while taking into account the carry at each stage.
So let's try your example:
A 5
1 7 +
We start at the least significant digits, 5 and 7, and perform the 1-digit addition. 516 + 716 = 1210. 1210 is less than 1610, so the output of our 1-digit add is 1210 = C16 with a carry of 0.
Now we add A and 1 (our carry-in is 0 so we can just add them normally). A16 + 116 = 1110. 1110 is less than 1610, so the output of our 1-digit add is 1110 = B16 with a carry of 0. (If we had a non-zero carry-in, we would just add 1 to this value.)
Hence, our overall result is:
A 5
1 7 +
-----
B C
I think we just remember the pattern of addition. Like following.
"0" + "0" = "0"
"0" + "1" = "1"
"0" + "2" = "2"
.
.
.
"f" + "d" = "1b"
"f" + "e" = "1c"
"f" + "f" = "1e"
We have dictionary of all of the pattern because we've learned it in school or somewhere. And we've also learned carry.
So I think this seems like manual addition algorithm.
Remembering the pattern include carry.
Calculating
Translate two digit to one digit(a+b->c).
Treat carry correctly.
And here is my code for that. But it may be a bit tricky.
import itertools
def add_hex(A,B):
A = "0"+A
B = "0"+B
#Remember all pattern include carry in variable d.
i2h = dict(zip(range(16), "0123456789abcdef"))
a = [(i,j) for i in "0123456789abcdef" for j in "0123456789abcdef"]
b = list(map(lambda t: int(t[0],16)+int(t[1],16), a))
c = ["0"+i2h[i] if i<16 else "1"+i2h[i-16] for i in b]#list of digit include carry
d = dict(zip(a,c))#d={(digit,digit):digit,,,}
#Calculate with variable d.
result = ""
cur = "0"
nex = "0"
for i in itertools.izip_longest(A[::-1], B[::-1], fillvalue = "0"):
cur = d[(nex, d[i][1])][1] #cur = carry + digit + digit
if d[i][0]=='1' or d[(nex, d[i][1])][0]=='1':#nex = carry = carry + digit + digit
nex = "1"
else:
nex = "0"
result += cur
return result[::-1]
#Test
A = "fedcba"
B = "012346"
print add_hex(A,B)
print hex(int(A,16)+int(B,16))#For validation
I hope it helps. :)

Categories

Resources