how can I assert that a number goes or a list grows up in TLA+? - tla+

I have a TLA+ spec where I would like to assert that a list only ever grows in length (it's fine if it stays the same when stuttering.)
Right now I have something like this, but I'm certain that it's not right:
NoWorkIsLost == Len(samples) = Len(samples) ~> Len(samples) = Len(samples) + 1
I'm not even sure what to search for here, I'm sure I'm missing something super obvious!

It depends on what you mean by "the list only ever grows in length". The simplest way to do that would be to write
Op == [][Len(samples') > Len(samples)]_Len(samples)
But that's saying that if the length changes, the length must increase. That still allows for you to mutate the list without changing it! If you instead write
Op == [][Len(samples') > Len(samples)]_samples
Then you are saying that if samples changes, it must also increase in length. But this allows you to pop one element and push two in a single action. You probably want to express that the old sequence is a prefix of the new one. You can do that with
Op == [][SubSeq(samples', 1, Len(samples)) = samples]_samples

Related

Minimax AI in python

I'm trying to create a minimax type AI which would go through 4 layers of moves and try to pick out the best possible move based on a certain heuristic. The thing is in my state machine if I ever reach a node which is an illegal move then I return the value None instead of a normal point value that my heuristic function would give. When dealing with this in my minimax function I'm kind of unsure how to go about it in the best way. So far it kind of looks like this and was wondering if this makes sense.
def ai_min_max(board, ai_mancala, player_mancala, ai_choices, player_choices, target_depth, cur_depth, maxTurn, position):
#base case where we call our heuristic function to tell us what the value of this state is
if cur_depth == target_depth :
#return the heuristic value for this state
return first_heuristic(board, ai_mancala, player_mancala, ai_choices, player_choices, position)
#if we are currently on a level where we are maximizing our function
if maxTurn :
#set the value to negative infinity
max_eval = float("-inf")
#go through the 10 possible choices you can make
for x in range(len(ai_choices)) :
new_position = position + [x]
my_eval = ai_min_max(board, ai_mancala, player_mancala, ai_choices, player_choices, target_depth, cur_depth +1, False, new_position)
#update the current max only if we have a valid movement, if not then do not update
if my_eval is not None:
max_eval = max(max_eval, my_eval)
if max_eval == float("-inf") :
return float("inf")
return max_eval
#if it is the minimizing player's turn
else :
min_eval = float("inf")
for x in range(len(player_choices)) :
new_position = position + [x]
my_eval = ai_min_max(board, ai_mancala, player_mancala, ai_choices, player_choices, target_depth, cur_depth +1, True, new_position)
if my_eval is not None:
min_eval = min(min_eval, my_eval)
#if there were no valid moves
if min_eval == float("inf") :
return float("-inf")
return min_eval
Typically in a minimax implementation you never actually make a recursive call on illegal moves - these are never generated in the first place. But, in some instances it can be easier (or less expensive) to actually apply the move to find out whether it is legal or not. For instance, if you have to apply a complex computation to find out if a move is legal, then you don't want to do it twice (once when you generate potential moves and once when you search on them). So, I will assume this is the case here.
Given this, does it make sense to return a special value as in your code above.
No, there is a better approach. At a min node you can return -inf to the parent when the move is illegal, and at a max node you can return inf to the parent. In this way, the illegal moves have the worse possible value, and will be handled naturally by the rest of the search without any other special cases. This makes the main minimax/alpha-beta loop much simpler.
The only complication to this is if a max player at the root has all moves losing it might return the illegal move. You can handle this case outside the main search - where testing a single move is very cheap compared to the full search - and just return any legal move if the move returned was illegal.

Connect string value to a corresponding variable name

This question has somehow to do with an earlier post from me. See here overlap-of-nested-lists-creates-unwanted-gap
I think that I have found a solution but i can't figure out how to implement it.
First the relevant code since I think it is easier to explain my problem that way. I have prepared a fiddle to show the code:
PYFiddle here
Each iteration fills a nested list in ag depending on the axis. The next iteration is supposed to fill the next nested list in ag but depending on the length of the list filled before.
The generell idea to realise this is as follows:
First I would assign each nested list within the top for-loop to a variable like that:
x = ag[0]
y = ag[1]
z = ag[2]
In order to identify that first list I need to access data_j like that. I think the access would work that way.
data_j[i-1]['axis']
data_j[i-1]['axis'] returns either x,y or z as string
Now I need to get the length of the list which corresponds to the axis returned from data_j[i-1]['axis'].
The problem is how do I connect the "value" of data_j[i-1]['axis'] with its corresponding x = ag[0], y = ag[1] or z = ag[2]
Since eval() and globals() are bad practice I would need a push into the right direction. I couldn't find a solution
EDIT:
I think I figured out a way. Instead of taking the detour of using the actual axis name I will try to use the iterator i of the parent loop (See the fiddle) since it increases for each element from data_j it kinda creates an id which I think I can use to create a method to use it for the index of the nest to address the correct list.
I managed to solve it using the iterator i. See the fiddle from my original post in order to comprehend what I did with the following piece of code:
if i < 0:
cond = 0
else:
cond = i
pred_axis = data_j[cond]['axis']
if pred_axis == 'x':
g = 0
elif pred_axis == 'y':
g = 1
elif pred_axis == 'z':
g = 2
calc_size = len(ag[g])
n_offset = calc_size+offset
I haven't figured yet why cond must be i and not i-1 but it works. As soon as I figure out the logic behind it I will post it.
EDIT: It doesn't work for i it works for i-1. My indices for the relevant list start at 1. ag[0] is reserved for a constant which can be added if necessary for further calculations. So since the relevant indices are moved up by the value of 1 from the beginning already i don't need to decrease the iterator in each run.

How to find all maximum value between every i and i + k(some constant) of a given array?

I need to find all maximum values among elements of every possible set {a[i], a[i+1],... a[i + k]} (where i is index and k is some given constant). For this I am using.
loop(b, 1, k) {
rloopl(i, b, n) {
if(a[i] < a[i-1])
a[i] = a[i-1];
}
}
but its too slow for large array. Is there any other more efficient way to do this?
I'm very sorry to tell you that, with the requirement as-presented, the answer would be: "no." If "the largest value could be anywhere," you have no choice but to "look ... everywhere."
If you are "doing this 'once and only once,'" for any particular data-set, then you're basically just gonna have to take your lumps. You're stuck with "brute-force."
However, if you're doing this more than once, and/or if you have some influence on the process by which the array in question gets loaded, the situation might start looking a little better.
For instance, if another piece of code is adding elements to this array one-at-a-time, it's trivial for that piece of code to notice the max/min value that it encounters. Code that loads a two-dimensional array might gather statistics about each row (column). And, so on. Such strategies, which are "free, at the time," can be used to eliminate (or, severely curtail) the need to do specific brute-force searches later.

i made the following binary search algorithm, and I am trying to improve it. suggestions?

i am doing a homework assignment where I have to check large lists of numbers for a given number. the list length is <= 20000, and I can be searching for just as many numbers. if the number we are searching for is in the list, return the index of that number, otherwise, return -1. here is what I did.
i wrote the following code, that outputsthe correct answer, but does not do it fast enough. it has to be done in less than 1 second.
here is my binary search code:`I am looking for suggestions to make it faster.
def binary_search(list1, target):
p = list1
upper = len(list1)
lower = 0
found = False
check = int((upper+lower)//2)
while found == False:
upper = len(list1)
lower = 0
check = int(len(list1)//2)
if list1[check] > target:
list1 = list1[lower:check]
check= int((len(list1))//2)
if list1[check] < target:
list1 = list1[check:upper]
check = int((len(list1))//2)
if list1[check] == target:
found = True
return p.index(target)
if len(list1)==1:
if target not in list1:
return -1`
grateful for any help/
The core problem is that this is not a correctly written Binary Search (see the algorithm there).
There is no need of index(target) to find the solution; a binary search is O(lg n) and so the very presence of index-of, being O(n), violates this! As written, the entire "binary search" function could be replaced as list1.index(value) as it is "finding" the value index simply to "find" the value index.
The code is also slicing the lists which is not needed1; simply move the upper/lower indices to "hone in" on the value. The index of the found value is where the upper and lower bounds eventually meet.
Also, make sure that list1 is really a list such that the item access is O(1).
(And int is not needed with //.)
1 I believe that the complexity is still O(lg n) with the slice, but it is a non-idiomatic binary search and adds additional overhead of creating new lists and copying the relevant items. It also doesn't allow the correct generation of the found item's index - at least without similar variable maintenance as found in a traditional implementation.
Try using else if's, for example if the value thats being checked is greater then you don't also need to check if its smaller.

Doesn't accept the list index?

I have this peice of code:
n = int (input ('Enter the Number of Players: '))
m = [[j] for j in range (0, n)]
all_names= []
i = 0
while n > 1:
m[i] = input('Player {0}: '.format (i+1))
all_names.extend ([m[i]])
if m[i][0] != m[i-1][-1]:
b= m.pop (i)
n = n-1
if all_names.count (m[i]) == 2:
n = n-1
b= m.pop (i)
i = i+1
It says the index is out of range (second if clause)
but I dont get it, why?
I hate to not answer your question directly, but what you're trying to do seems... really confusing. Python has a sort of rule that there's supposed to be a really clear, clean way of doing things, so if a piece of code looks really funky (especially for such a simple function), it's probably not using the right approach.
If you just want to create a container of names, there are numerous simpler ways of doing it:
players=int(input("How many players?\n"))
player_names=set()
while len(player_names)<players:
player_names.add(input("What is player {}'s name?\n".format(len(player_names)+1)))
... will give you a set of unique player names, although this won't be ordered. That might matter (your implementation kept order, so maybe it is), and in this case you could still use a list and add a small check to make sure you were adding a new name and not repeatedly adding names:
players=int(input("How many players?\n"))
player_names=list()
while len(player_names)<players:
playname=input("What is player {}'s name?\n".format(len(player_names)+1))
if playname not in player_names:
player_names.append(playname)
I'm open to someone haranguing me about dodging the question, particularly if there's a purpose/reason for the approach the questioner took.
Length of m decreases every time the code enters the first if clause. However, you increment the value of i in each iteration. So, at the midpoint of length of m (if the 1st clause is entered always) or a little later, the value of i will be bigger than the value of m and you will get an index out of range.

Resources