0

I read and understand the whole article described in other question.

My problem is regarding this source code.

the author returns values in function assign:

def assign(values, s, d):
    """Eliminate all the other values (except d) from values[s] and propagate.
    Return values, except return False if a contradiction is detected."""
    other_values = values[s].replace(d, '')
    if all(eliminate(values, s, d2) for d2 in other_values):
        return values
    else:
        return False

But assign is never used to set existing variable values in calling function parse_grid(grid):

def parse_grid(grid):
    values = dict((s, digits) for s in squares)
    for s,d in grid_values(grid).items():
        if d in digits and not assign(values, s, d):
            return False ## (Fail if we can't assign d to square s.)
    return values

So returning values seems rather unnecessary to me. Since he only uses assign() as a boolean, can't he just return true instead?

I understood that returning a value doesn't change anything about the original variable. Only if the variable is passed as parameter and changed there without getting rebound to another variable, only then does the 'original' variable change because it holds the same reference.

However the return values in def parse_grid(grid) should be a totally changed values then the one at the start of the function. When does this get assigned?

Question:

Where does values in def parse_grid(grid) get changed? Because this function returns values and this returned values should not be the same as the one set at start of this function. So where did it get changed and how?

It is called for example like this: display(parse_grid(grid2))

Community
  • 1
  • 1
dylanmensaert
  • 1,689
  • 5
  • 24
  • 39

3 Answers3

2

The assign function is called multiple times. For example, in the search function:

def search(values):
    "Using depth-first search and propagation, try all possible values."
    if values is False:
        return False ## Failed earlier
    if all(len(values[s]) == 1 for s in squares): 
        return values ## Solved!
    ## Chose the unfilled square s with the fewest possibilities
    n,s = min((len(values[s]), s) for s in squares if len(values[s]) > 1)
    return some(search(assign(values.copy(), s, d)) 
        for d in values[s])

The return value of assign is passed into search to continue the depth-first-search.

arknave
  • 603
  • 1
  • 6
  • 16
  • Ok, but then where did values got changed in def parse_grid(grid):? Because he tests it out without the use of search() first. And he gets a totally changed values (solved sudoku). – dylanmensaert Mar 16 '13 at 22:05
2

Let us take a look at this function:

def parse_grid(grid):
    values = dict((s, digits) for s in squares)
    for s,d in grid_values(grid).items():
        if d in digits and not assign(values, s, d):
            return False ## (Fail if we can't assign d to square s.)
    return values

Here the function returns a new dict. It returns it so that the caller can do something with it. The function doesn't return True because the caller wants to obtain and use that new dict.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • But it should return a changed dict. Where did values change in this method? – dylanmensaert Mar 16 '13 at 22:04
  • It doesn't return a changed dict. It returns a brand new dict. Created by the invocation of the `dict()` constructor. – David Heffernan Mar 16 '13 at 22:05
  • But then how does he get a totally solved sudoku with display(parse_grid(grid2))? I though values = dict((s, digits) for s in squares) starts with a sudoku where all possibilities of all squares are mentioned. Then he does his assign function, and pof, in parse_grid(), he returns a values where sudoku is solved?! – dylanmensaert Mar 16 '13 at 22:07
  • Er, I don't know. Is this question going to morph into explaining all of that code? – David Heffernan Mar 16 '13 at 22:08
  • Now, just that part.. The change has to happen in that function, doesn't it? How else can value be set? I'm not asking how it works, just trying to understand WHERE values in parse_grid() get changed so he returns a different values.. Srry for any unclarity on my part, I'm bad at explaining > – dylanmensaert Mar 16 '13 at 22:08
  • I don't really understand what you are getting at. Look at the code in parse_grid where values is of local scope and is of course created in that function. And then returned. So values is not changed at all. It's not passed in. It's a local. It's created and returned. – David Heffernan Mar 16 '13 at 22:10
  • I think, judging from this question and your other one, that you need to get on top of Python. At the moment you are suffering from a lot of erroneous beliefs about how it works. This code seems exceedingly opaque for you to be cutting your teeth on. – David Heffernan Mar 16 '13 at 22:17
  • I'm sorry to bother you :) I think I found it myself. Is it right if I say that values get changed because he keeps passing the parameter to another function (eliminate), where it gets changed there. And because the reference is still correct, the original values changes. Is that correct? – dylanmensaert Mar 16 '13 at 22:20
1

In the code you display, assign seems underused. You are right: it is only used to check the validity of the values (a no-contradiction test). So, as you say, returning true would do the trick.

But since assign can do more, why cripple it? It may be useful elsewhere in the code.


Edit: and it actually is. Looking at the linked code the function search calls it and uses the return values.

Jean
  • 7,623
  • 6
  • 43
  • 58