m-labs / artiq

A leading-edge control system for quantum information experiments
https://m-labs.hk/artiq
GNU Lesser General Public License v3.0
434 stars 201 forks source link

Compiler: Array Declaration uses references #1304

Closed drewrisinger closed 5 years ago

drewrisinger commented 5 years ago

Bug Report

One-Line Summary

Issues with references when allocating multi-dimensional array on core.

Issue Details

Steps to Reproduce

Sample code:

import artiq
from artiq.language import kernel

class TwoDimensionalArrayTest(artiq.language.environment.EnvExperiment):
    """Check if 2-D arrays can be created & manipulated on core."""

    def build(self):
        """Declare needed devices."""
        self.setattr_device("core")

    @kernel
    def run(self):
        """Run tests on 2D arrays."""
        self.test_python_array()    # DOES NOT WORK
        self.test_python_array_2()

    @kernel
    def test_python_array(self):
        """Test using an allocated multiplied array (DOES NOT WORK).

        This seems to have some sort of problem with referencing.
        """
        # ALLOCATION DOES NOT WORK
        x_len = 10
        y_len = 5
        arr = [[0] * x_len] * y_len

        counter = 0
        for i in range(y_len):
            for j in range(x_len):
                arr[i][j] = counter
                counter += 1

        print("Python method 1 (BROKEN)")
        print(arr)

    @kernel
    def test_python_array_2(self):
        """Test using an explicitly allocated array (WORKS)."""
        x_len = 10
        y_len = 5
        arr = [[0 for i in range(x_len)] for j in range(y_len)]

        counter = 0
        for i in range(y_len):
            for j in range(x_len):
                arr[i][j] = counter
                counter += 1

        print("Python method 2")
        print(arr)

Expected Behavior

Both methods should do produce exactly the same behavior

Actual (undesired) Behavior

Your System

whitequark commented 5 years ago

This is the correct behavior. If you run your "broken" test_python_array method on the host Python, you will get the exact same result.

drewrisinger commented 5 years ago

Fine. That seems like an inconsistent use of pass-by-reference/pass-by-value in the Python interpreter, though. Odd.

sbourdeauducq commented 5 years ago

It is consistent (even if perhaps confusing) - you just have to know that the * operator on a list does a shallow copy of the element. Does the code below make it clearer?

>>> x = [0]
>>> id(x)
140512082107016
>>> l=[x]*2
>>> l
[[0], [0]]
>>> l[0][0] = 1
>>> l
[[1], [1]]
>>> id(l[0])
140512082107016
>>> id(l[1])
140512082107016