<commit_before># Author: Enric Tejedor CERN  01/2019

################################################################################
# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.                      #
# All rights reserved.                                                         #
#                                                                              #
# For the licensing terms see $ROOTSYS/LICENSE.                                #
# For the list of contributors see $ROOTSYS/README/CREDITS.                    #
################################################################################

from ROOT import pythonization
import cppyy

# Python-list-like methods

def _remove_pyz(self, o):
    # Parameters:
    # - self: collection
    # - o: object to remove from the collection
    res = self.Remove(o)

    if not res:
        raise ValueError('list.remove(x): x not in list')

def _extend_pyz(self, c):
    # Parameters:
    # - self: collection
    # - c: collection to extend self with
    it = iter(c)
    for _ in range(len(c)):
        self.Add(next(it))

def _count_pyz(self, o):
    # Parameters:
    # - self: collection
    # - o: object to be counted in the collection
    # Returns:
    # - Number of occurrences of the object in the collection
    n = 0

    for elem in self:
        if elem == o:
            n += 1

    return n

# Python operators

def _add_pyz(self, c):
    # Parameters:
    # - self: first collection to be added
    # - c: second collection to be added
    # Returns:
    # - self + c
    res = self.__class__()
    _extend_pyz(res, self)
    _extend_pyz(res, c)
    return res

def _mul_pyz(self, n):
    # Parameters:
    # - self: collection to be multiplied
    # - n: factor to multiply the collection by
    # Returns:
    # - self * n
    res = self.__class__()
    for _ in range(n):
        _extend_pyz(res, self)
    return res

def _imul_pyz(self, n):
    # Parameters:
    # - self: collection to be multiplied (in place)
    # - n: factor to multiply the collection by
    # Returns:
    # - self *= n
    for _ in range(n - 1):
        _extend_pyz(self, self)
    return self

# Python iteration

def _iter_pyz(self):
    # Generator function to iterate on TCollections
    # Parameters:
    # - self: collection to be iterated
    it = cppyy.gbl.TIter(self)
    # TIter instances are iterable
    for o in it:
        yield o

@pythonization()
def pythonize_tcollection(klass, name):
    # Parameters:
    # klass: class to be pythonized
    # name: string containing the name of the class

    if name == 'TCollection':
        # Support `len(c)` as `c.GetEntries()`
        klass.__len__ = klass.GetEntries

        # Add Python lists methods
        klass.append = klass.Add
        klass.remove = _remove_pyz
        klass.extend = _extend_pyz
        klass.count = _count_pyz

        # Define Python operators
        klass.__add__ = _add_pyz
        klass.__mul__ = _mul_pyz
        klass.__rmul__ = _mul_pyz
        klass.__imul__ = _imul_pyz

        # Make TCollections iterable
        klass.__iter__ = _iter_pyz

    return True
<commit_msg>[Exp PyROOT] Fix c *= factor operator for TCollection<commit_after># Author: Enric Tejedor CERN  01/2019

################################################################################
# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.                      #
# All rights reserved.                                                         #
#                                                                              #
# For the licensing terms see $ROOTSYS/LICENSE.                                #
# For the list of contributors see $ROOTSYS/README/CREDITS.                    #
################################################################################

from ROOT import pythonization
import cppyy

# Python-list-like methods

def _remove_pyz(self, o):
    # Parameters:
    # - self: collection
    # - o: object to remove from the collection
    res = self.Remove(o)

    if not res:
        raise ValueError('list.remove(x): x not in list')

def _extend_pyz(self, c):
    # Parameters:
    # - self: collection
    # - c: collection to extend self with
    it = iter(c)
    for _ in range(len(c)):
        self.Add(next(it))

def _count_pyz(self, o):
    # Parameters:
    # - self: collection
    # - o: object to be counted in the collection
    # Returns:
    # - Number of occurrences of the object in the collection
    n = 0

    for elem in self:
        if elem == o:
            n += 1

    return n

# Python operators

def _add_pyz(self, c):
    # Parameters:
    # - self: first collection to be added
    # - c: second collection to be added
    # Returns:
    # - self + c
    res = self.__class__()
    _extend_pyz(res, self)
    _extend_pyz(res, c)
    return res

def _mul_pyz(self, n):
    # Parameters:
    # - self: collection to be multiplied
    # - n: factor to multiply the collection by
    # Returns:
    # - self * n
    res = self.__class__()
    for _ in range(n):
        _extend_pyz(res, self)
    return res

def _imul_pyz(self, n):
    # Parameters:
    # - self: collection to be multiplied (in place)
    # - n: factor to multiply the collection by
    # Returns:
    # - self *= n
    c = self.__class__()
    c.AddAll(self)
    for _ in range(n - 1):
        _extend_pyz(self, c)
    return self

# Python iteration

def _iter_pyz(self):
    # Generator function to iterate on TCollections
    # Parameters:
    # - self: collection to be iterated
    it = cppyy.gbl.TIter(self)
    # TIter instances are iterable
    for o in it:
        yield o

@pythonization()
def pythonize_tcollection(klass, name):
    # Parameters:
    # klass: class to be pythonized
    # name: string containing the name of the class

    if name == 'TCollection':
        # Support `len(c)` as `c.GetEntries()`
        klass.__len__ = klass.GetEntries

        # Add Python lists methods
        klass.append = klass.Add
        klass.remove = _remove_pyz
        klass.extend = _extend_pyz
        klass.count = _count_pyz

        # Define Python operators
        klass.__add__ = _add_pyz
        klass.__mul__ = _mul_pyz
        klass.__rmul__ = _mul_pyz
        klass.__imul__ = _imul_pyz

        # Make TCollections iterable
        klass.__iter__ = _iter_pyz

    return True
<|endoftext|>


<commit_before>"""
Hierarchy of PlotGroup classes, i.e. output-device-independent sets of plots.

Includes PlotGroups for standard plots of anything in a Sheet database,
plus weight plots for one unit, and projections.

$Id$
"""
__version__='$Revision$'

import types
from itertools import chain

from Numeric import transpose, array, ravel

from topo.base.utils import flatten, dict_sort
from topo.base.topoobject import TopoObject
from topo.base.sheet import Sheet
from topo.base.sheetview import SheetView
from topo.base.connectionfield import CFSheet

from plot import Plot, make_plot
import bitmap

### JABALERT: This constant should be removed for now, though it may
### be reinstated some day.
FLAT = 'FLAT'

def sort_plots(plot_list):
    """Sort a (static) plot list according to the src_names."""
    plot_list.sort(lambda x, y: cmp(x.view_info['src_name'], y.view_info['src_name']))

### JCALERT! This file has been largely modified so that now, each PlotGroup creates
### its plot_list itself, instead of the PlotEngine doing it. The PlotEngine only
### creates and stores the PlotGroup in this new version of the code.It is the first version
### and it still remains job to be done for clarifying and improving it.

class PlotGroup(TopoObject):
    """
    Container that has one or more Plots and also knows how to arrange
    the plots and other special parameters.
    """

    ### JCALERT:
    ### - plot_list may disappear. For that we need to work on the special case of inputparampanel.
    ### - re-arranged the order and look at the call in all panel classes (i.e. inputparampanel)
    ### also review the doc of each functions.
    ### - rewrite the test file.

    def __init__(self,simulator,template,plot_group_key,sheet_name=None,plot_list=[],shape=FLAT,**params):
        """
        plot_list can be of two types:
        1.  A list of Plot objects that can return bitmaps when requested.
        2.  Can also be a function that returns a list of plots so
        that each time plot() is called, an updated list is created for the
        latest list of sheets in the simulation.
        """
        super(PlotGroup,self).__init__(**params)
        self.all_plots = []
        self.added_list = []

        # Shape of the plotting display used by PlotGroup.
        #
        # Allowable shapes include:
        ### JABALERT: What shapes are already supported, right now?
        #
        # In the future, it might be good to be able to specify the
        # plot rows and columns using tuples.  For instance, if three
        # columns are desired with the plots laid out from left to
        # right, we could use (None, 3).  If three rows are desired
        # then (3, None).  Another method that would work is [3,2,4]
        # would have the first row with 3, the second row with 2, the
        # third row with 4, etc.  The default left-to-right ordering
        # in one row could perhaps be represented as (None, Inf).
        self.shape = shape

        self.plot_group_key = plot_group_key
        self.bitmaps = []
        self.template = template

	# If no sheet_name is defined, the sheet_filter_lam accepts all sheets
        if sheet_name:
	    self.sheet_filter_lam = lambda s: s.name == sheet_name
        else:
            self.sheet_filter_lam = lambda s : True

	self.simulator = simulator

	self.plot_list = lambda: self.initialize_plot_list(plot_list)

    ### JCALERT! we might want this function to be private.
    def initialize_plot_list(self,plot_list):
        """
        Procedure that is called when creating a PlotGroup, that return the plot_list attribute
        i.e. the list of plot that are specified by the PlotGroup template.

        This function calls create_plots, that is implemented in each PlotGroup subclasses.
        (In particular, this needs to be different for UnitWeightsPlotGroup and ProjectionPlotGroup)
        """

	sheet_list = [each for each in dict_sort(self.simulator.objects(Sheet)) if self.sheet_filter_lam(each)]

        # Loop over all sheets that passed the filter.
        #     Loop over each individual PlotTemplate:
        #         Call the create_plots function to create the according plot
        for each in sheet_list:
	    ### JCALERT! This test can be later removed when improving testpattern.py
	    if self.template != None :
		for (pt_name,pt) in self.template.plot_templates:
		    plot_list= plot_list + self.create_plots(pt_name,pt,each)

    	return plot_list

    def create_plots(self):
        """
	This function need to be re-implemented in the subclass.
	As it is implemented here, it leaves the possibility of passing a plot_list
        of already created plots when creating a PlotGroup.
	"""

	return []

    ### JABHACKALERT!
    ###
    ### Shouldn't this raise NotImplementedError instead of passing?
    ### If implementing it is required, not optional, then it must.

    ### JCALERT! it is not clear what this function is doing anyway, or the name
    ### should be changed or it should be spared. (To do, I will get rid of it)
    ### That would require a re-organization of the way Plot are created in the sub-PlotGroup

    def do_plot_cmd(self):
        """
        Command called when plots need to be generated.

        Subclasses of PlotGroup will need to create this function.
        """
        pass

    def load_images(self):
        """
        Pre:  do_plot_cmd() has already been called, so plots() will return
              valid plots.
        Post: self.bitmaps contains a list of topo.bitmap objects or None if
              no valid maps were available.

        Returns: List of bitmaps.  self.bitmaps also has been updated.
        """
        self.bitmaps = []
        for each in self.plots():

            win = each.bitmap
            win.view_info = each.view_info

            self.bitmaps.append(win)
        return self.bitmaps

    def add(self,new_plot):
        """
        new_plot can be a single Plot, or it can be a list of plots.
        Either way, it will be properly added to the end of self.plot_list.
        """

	self.added_list.extend(new_plot)

    ### JCALERT ! It has to be redefined how this function release_sheet_view() works
    ### here but also in sheet and connectionfield and Plot.
    def release_sheetviews(self):
        """
        Call release_sheetviews() on all Plots in plot list, to free
        up Sheet.sheet_view_dict entries and save memory.  Note, not
        all plots use SheetViews stored in a Sheet dictionary.
        """
        for each in self.all_plots:
            each.release_sheetviews()

    ### JCALERT! The call to this function is done when we want the list.
    ### so there is no need to explicitly call it from outside if not to use this list
    ### (see the do_plot_cmd in most of the PlotGroupPanels).
    def plots(self):
        """
        Generate the bitmap lists.
        """
        bitmap_list = []

	self.all_plots = flatten(self.plot_list()) + self.added_list

        generated_bitmap_list = [each for each in self.all_plots if each != None]

        ### JCALERT! For each plotgroup, we want the plot to be displayed
        ### in the alphabetical order according to their view_info['src_name']
        ### The only PlotGroup that does not have to do that is the projectionplotgroup
        ### and that is why this function is overwritten.
        ### (It has to be fixed, as well as the handling of plot label in general)
        sort_plots(generated_bitmap_list)

        return generated_bitmap_list

class BasicPlotGroup(PlotGroup):
    """
    PlotGroup for Activity SheetViews
    """
    ### JCALERT! See what to do for the default value (sheet_filter_lam =None, plot_list=None)
    def __init__(self,simulator,template,plot_group_key,sheet_filter_lam,plot_list,**params):
        super(BasicPlotGroup,self).__init__(simulator,template,plot_group_key,sheet_filter_lam,plot_list,
                                            **params)

    def create_plots(self,pt_name,pt,sheet):

	### JCALERT! Normalize should be directly get from plot_channels in Plot instead of here
        ### Same Alert in UnitWeight and Projection PlotGroup.
	plot_channels = pt
        n = pt.get('Normalize',False)
	plot_name = '\n'+pt_name
        p = make_plot(plot_channels,sheet.sheet_view_dict,sheet.density,sheet.bounds,n,False,name=plot_name)
	return [p]

class UnitWeightsPlotGroup(PlotGroup):
    """
    PlotGroup for Weights UnitViews
    """

    def __init__(self,simulator,template,plot_group_key,sheet_filter_lam,plot_list,**params):

        self.x = float(plot_group_key[2])
        self.y = float(plot_group_key[3])

        # Decides wether the plots of the UnitWeightPlotGroup are situated on
        # a plot of the full source sheet, or not.
      	self.situate = False

	super(UnitWeightsPlotGroup,self).__init__(simulator,template,plot_group_key,sheet_filter_lam,plot_list,
						  **params)

    def create_plots(self,pt_name,pt,sheet):

	plot_list = []
        if not isinstance(sheet,CFSheet):
            self.warning('Requested weights view from other than CFSheet.')
        else:
            for p in set(flatten(sheet.in_projections.values())):
		### JCALERT! This has to be clarified somewhere: the sheet_view for a
		### weight belongs to the src_sheet, and the name in the key
                ### is the destination sheet.
	        plot_channels = pt

	        ### JCALERT! do the plot_channels['Strength'] == 'weights' test
                ### here and in projectionplotgroup
                key = ('Weights',sheet.name,p.name,self.x,self.y)
		plot_name = '\n(from ' + p.src.name +')'
		plot_channels['Strength'] = key
		plot_list.append(make_plot(plot_channels,p.src.sheet_view_dict,p.src.density,
				      p.src.bounds,pt['Normalize'],self.situate,name=plot_name))

        self.debug('plot_list =' + str(plot_list))
        return plot_list

    ### JCALERT! I am not sure this function is of any use here, it should be put in another place...
    ### or, change the name of it so that it is clearer when called for the PlotGroupPanels
    def do_plot_cmd(self):
        """
        Lambda function passed in, that will filter out all sheets
        except the one with the name being looked for.
        """
        sheets = self.simulator.objects(Sheet).values()
        for each in sheets:
            if self.sheet_filter_lam(each):
		### JCALERT! It is confusing that the method unit_view is only defined in the
                ### CFSheet class, and that we are supposed to manipulate sheets here.
		### also, it is supposed to return a view, but here it is used as a procedure.
                each.unit_view(self.x,self.y)

class ProjectionPlotGroup(PlotGroup):
    """
    PlotGroup for Projection Plots
    """

    def __init__(self,simulator,template,plot_group_key,sheet_filter_lam,plot_list,**params):

        self.weight_name = plot_group_key[1]
        self.density = float(plot_group_key[2])
        self.shape = (0,0)
	self.situate = False

        super(ProjectionPlotGroup,self).__init__(simulator,template,plot_group_key,sheet_filter_lam,
                                                   plot_list,**params)

        self._sim_ep = [s for s in self.simulator.objects(Sheet).values()
                        if self.sheet_filter_lam(s)][0]
        self._sim_ep_src = self._sim_ep.get_in_projection_by_name(self.weight_name)[0].src

    def create_plots(self,pt_name,pt,sheet):

	### JCALERT This has to be solved: projection is a list here!
        ### for the moment the hack below deal with that.
        ### Also, why do we pass the template here?

        projection = sheet.get_in_projection_by_name(pt['Projection_name'])
        plot_list=[]
        if projection:
	    src_sheet=projection[0].src
	    projection=projection[0]

	    for view in self.view_list:
		plot_channels = pt
		### JCALERT! Do the test pt['Strength']='Weights' here
		key = ('Weights',sheet.name,projection.name,view.view_info['x'],view.view_info['y'])
		plot_channels['Strength'] = key
		plot_list.append(make_plot(plot_channels,src_sheet.sheet_view_dict,
                                      src_sheet.density,src_sheet.bounds,pt['Normalize'],self.situate))

        return plot_list

    def _generate_coords(self):
        """
        Evenly space out the units within the sheet bounding box, so
        that it doesn't matter which corner the measurements start
        from.  A 4 unit grid needs 5 segments.  List is in left-to-right,
        from top-to-bottom.
        """
        def rev(x): y = x; y.reverse(); return y

        aarect = self._sim_ep.bounds.aarect()
        (l,b,r,t) = aarect.lbrt()
        x = float(r - l)
        y = float(t - b)
        x_step = x / (int(x * self.density) + 1)
        y_step = y / (int(y * self.density) + 1)
        l = l + x_step
        b = b + y_step
        coords = []
        self.shape = (int(x * self.density), int(y * self.density))
        for j in rev(range(self.shape[1])):
            for i in range(self.shape[0]):
                coords.append((x_step*i + l, y_step*j + b))

        return coords

    def do_plot_cmd(self):
        coords = self._generate_coords()

        full_unitview_list = [self._sim_ep.unit_view(x,y) for (x,y) in coords]

	### JCALERT! The use of chain and nested list here and in
        ### connectionfield.py (unit_view) can be spared or made simpler.

        self.view_list = [view for view in chain(*full_unitview_list)
                         if view.projection.name == self.weight_name]

    ### JCALERT ! for the moment this function is re-implemented only for ProjectionGroup
    ### because we do not want the plots to be sorted according to their src_name in this case
    def plots(self):
        """
        Generate the bitmap lists.
        """
        bitmap_list = []

	self.debug('Dynamic plotgroup')
	self.all_plots = flatten(self.plot_list()) + self.added_list
	self.debug('all_plots = ' + str(self.all_plots))

        generated_bitmap_list = [each for each in self.all_plots if each !=None]
        return generated_bitmap_list

<commit_msg>Cleaned up the comments. Made initialize_plot_list (semi) private.<commit_after>"""
Hierarchy of PlotGroup classes, i.e. output-device-independent sets of plots.

Includes PlotGroups for standard plots of anything in a Sheet database,
plus weight plots for one unit, and projections.

$Id$
"""
__version__='$Revision$'

import types
from itertools import chain

from Numeric import transpose, array, ravel

from topo.base.utils import flatten, dict_sort
from topo.base.topoobject import TopoObject
from topo.base.sheet import Sheet
from topo.base.sheetview import SheetView
from topo.base.connectionfield import CFSheet

from plot import Plot, make_plot
import bitmap

### JABALERT: This constant should be removed for now, though it may
### be reinstated some day.
FLAT = 'FLAT'

def sort_plots(plot_list):
    """Sort a (static) plot list according to the src_names."""
    plot_list.sort(lambda x, y: cmp(x.view_info['src_name'], y.view_info['src_name']))

### JCALERT! This file has been largely modified so that now, each PlotGroup creates
### its plot_list itself, instead of the PlotEngine doing it. The PlotEngine only
### creates and stores the PlotGroup in this new version of the code.It is the first version
### and it still remains job to be done for clarifying and improving it.

class PlotGroup(TopoObject):
    """
    Container that has one or more Plots and also knows how to arrange
    the plots and other special parameters.
    """

    ###JCALERT:
    ### - re-arranged the order and look at the call in all panel classes (i.e. inputparampanel)
    ### also review the doc of each functions.
    ### - rewrite the test file.

    def __init__(self,simulator,template,plot_group_key,sheet_name=None,plot_list=[],shape=FLAT,**params):
        """
        plot_list can be of two types:
        1.  A list of Plot objects that can return bitmaps when requested.
        2.  Can also be a function that returns a list of plots so
        that each time plot() is called, an updated list is created for the
        latest list of sheets in the simulation.
        """
        super(PlotGroup,self).__init__(**params)
        self.all_plots = []
        self.added_list = []

        # Shape of the plotting display used by PlotGroup.
        #
        # Allowable shapes include:
        ### JABALERT: What shapes are already supported, right now?
        #
        # In the future, it might be good to be able to specify the
        # plot rows and columns using tuples.  For instance, if three
        # columns are desired with the plots laid out from left to
        # right, we could use (None, 3).  If three rows are desired
        # then (3, None).  Another method that would work is [3,2,4]
        # would have the first row with 3, the second row with 2, the
        # third row with 4, etc.  The default left-to-right ordering
        # in one row could perhaps be represented as (None, Inf).
        self.shape = shape

        self.plot_group_key = plot_group_key
        self.bitmaps = []
        self.template = template

	# If no sheet_name is defined, the sheet_filter_lam accepts all sheets
        if sheet_name:
	    self.sheet_filter_lam = lambda s: s.name == sheet_name
        else:
            self.sheet_filter_lam = lambda s : True

	self.simulator = simulator

	self.plot_list = lambda: self._initialize_plot_list(plot_list)

    def _initialize_plot_list(self,plot_list):
        """
        Procedure that is called when creating a PlotGroup, that return the plot_list attribute
        i.e. the list of plot that are specified by the PlotGroup template.

        This function calls create_plots, that is implemented in each PlotGroup subclasses.
        (In particular, this needs to be different for UnitWeightsPlotGroup and ProjectionPlotGroup)
        """
	sheet_list = [each for each in dict_sort(self.simulator.objects(Sheet)) if self.sheet_filter_lam(each)]
        # Loop over all sheets that passed the filter.
        #     Loop over each individual PlotTemplate:
        #         Call the create_plots function to create the according plot
        for each in sheet_list:
	    ### JCALERT! This test can be later removed when improving testpattern.py
            ### (for the moment call to PlotGroup from testpattern lead to self.template=None
	    if self.template != None :
		for (pt_name,pt) in self.template.plot_templates:
		    plot_list= plot_list + self.create_plots(pt_name,pt,each)
    	return plot_list

    def create_plots(self):
        """
	This function need to be re-implemented in the subclass.
	As it is implemented here, it leaves the possibility of passing a plot_list
        of already created plots when creating a PlotGroup.
	"""
	return []

    ### JCALERT! do_plot_cmd() should be deleted here and in all sub-classes
    ### and be replaced by the command assigned from the PlotGroupTemplate
    ### (e.g measure_or_pref,measure_activity) and executed from the panel class.
    ### All these function will have to go in a special separate file
    ### (measure_or_pref and measure_activity being in analysis/featuremap.py for the moment).
    ### That will also enable to makes the different panel acting more uniformly,
    ### and might allow to delete basicplotgrouppanel.py
    def do_plot_cmd(self):
        """
        Command called when plots need to be generated.

        Subclasses of PlotGroup will need to create this function.
        """
        pass

    def load_images(self):
        """
        Pre:  do_plot_cmd() has already been called, so plots() will return
              valid plots.
        Post: self.bitmaps contains a list of topo.bitmap objects or None if
              no valid maps were available.

        Returns: List of bitmaps.  self.bitmaps also has been updated.
        """
        self.bitmaps = []
        for each in self.plots():
            win = each.bitmap
            win.view_info = each.view_info
            self.bitmaps.append(win)
        return self.bitmaps

    def add(self,new_plot):
        """
        new_plot can be a single Plot, or it can be a list of plots.
        Either way, it will be properly added to the end of self.plot_list.
        """
	self.added_list.extend(new_plot)

    ### JCALERT ! It has to be redefined how this function release_sheet_view() works
    ### here but also in sheet and connectionfield and Plot.
    def release_sheetviews(self):
        """
        Call release_sheetviews() on all Plots in plot list, to free
        up Sheet.sheet_view_dict entries and save memory.  Note, not
        all plots use SheetViews stored in a Sheet dictionary.
        """
        for each in self.all_plots:
            each.release_sheetviews()

    ### JCALERT! The call to this function is done when we want the list.
    ### so there is no need to explicitly call it from outside if not to use this list
    ### (see the do_plot_cmd in most of the PlotGroupPanels).
    def plots(self):
        """
        Generate the bitmap lists.
        """
        bitmap_list = []
	self.all_plots = flatten(self.plot_list()) + self.added_list
        generated_bitmap_list = [each for each in self.all_plots if each != None]
        ### JCALERT! For each plotgroup, we want the plot to be displayed
        ### in the alphabetical order according to their view_info['src_name']
        ### The only PlotGroup that does not have to do that is the projectionplotgroup
        ### and that is why this function is overwritten.
        ### (It has to be fixed, as well as the handling of plot label in general)
        sort_plots(generated_bitmap_list)
        return generated_bitmap_list

class BasicPlotGroup(PlotGroup):
    """
    PlotGroup for Activity SheetViews
    """
    ### JCALERT! See what to do for the default value (sheet_filter_lam =None, plot_list=None)
    def __init__(self,simulator,template,plot_group_key,sheet_filter_lam,plot_list,**params):
        super(BasicPlotGroup,self).__init__(simulator,template,plot_group_key,sheet_filter_lam,plot_list,
                                            **params)

    def create_plots(self,pt_name,pt,sheet):

	plot_channels = pt
        ### JCALERT! Normalize should be directly get from plot_channels in Plot instead of here
        ### Same thing in UnitWeight and Projection PlotGroup.
        n = pt.get('Normalize',False)
	plot_name = '\n'+pt_name
        p = make_plot(plot_channels,sheet.sheet_view_dict,sheet.density,sheet.bounds,n,False,name=plot_name)
	return [p]

class UnitWeightsPlotGroup(PlotGroup):
    """
    PlotGroup for Weights UnitViews
    """

    def __init__(self,simulator,template,plot_group_key,sheet_filter_lam,plot_list,**params):

        self.x = float(plot_group_key[2])
        self.y = float(plot_group_key[3])

        # Decides wether the plots of the UnitWeightPlotGroup are situated on
        # a plot of the full source sheet, or not.
      	self.situate = False

	super(UnitWeightsPlotGroup,self).__init__(simulator,template,plot_group_key,sheet_filter_lam,plot_list,
						  **params)

    def create_plots(self,pt_name,pt,sheet):

	plot_list = []
        if not isinstance(sheet,CFSheet):
            self.warning('Requested weights view from other than CFSheet.')
        else:
            for p in set(flatten(sheet.in_projections.values())):
		### JCALERT! This has to be clarified somewhere: the sheet_view for a
		### weight belongs to the src_sheet, and the name in the key
                ### is the destination sheet.
	        plot_channels = pt

	        ### JCALERT! do the plot_channels['Strength'] == 'weights' test
                ### here and in projectionplotgroup
                key = ('Weights',sheet.name,p.name,self.x,self.y)
		plot_name = '\n(from ' + p.src.name +')'
		plot_channels['Strength'] = key
		plot_list.append(make_plot(plot_channels,p.src.sheet_view_dict,p.src.density,
				      p.src.bounds,pt['Normalize'],self.situate,name=plot_name))

        self.debug('plot_list =' + str(plot_list))
        return plot_list

    ### JCALERT! I am not sure this function is of any use here, it should be put in another place...
    ### or, change the name of it so that it is clearer when called for the PlotGroupPanels
    def do_plot_cmd(self):
        """
        Lambda function passed in, that will filter out all sheets
        except the one with the name being looked for.
        """
        sheets = self.simulator.objects(Sheet).values()
        for each in sheets:
            if self.sheet_filter_lam(each):
		### JCALERT! It is confusing that the method unit_view is only defined in the
                ### CFSheet class, and that we are supposed to manipulate sheets here.
		### also, it is supposed to return a view, but here it is used as a procedure.
                each.unit_view(self.x,self.y)

class ProjectionPlotGroup(PlotGroup):
    """
    PlotGroup for Projection Plots
    """

    def __init__(self,simulator,template,plot_group_key,sheet_filter_lam,plot_list,**params):

        self.weight_name = plot_group_key[1]
        self.density = float(plot_group_key[2])
        self.shape = (0,0)
	self.situate = False

        super(ProjectionPlotGroup,self).__init__(simulator,template,plot_group_key,sheet_filter_lam,
                                                   plot_list,**params)

        self._sim_ep = [s for s in self.simulator.objects(Sheet).values()
                        if self.sheet_filter_lam(s)][0]
        self._sim_ep_src = self._sim_ep.get_in_projection_by_name(self.weight_name)[0].src

    def create_plots(self,pt_name,pt,sheet):

	### JCALERT This has to be solved: projection is a list here!
        ### for the moment the hack below deal with that.
        ### Also, why do we pass the template here?

        projection = sheet.get_in_projection_by_name(pt['Projection_name'])
        plot_list=[]
        if projection:
	    src_sheet=projection[0].src
	    projection=projection[0]

	    for view in self.view_list:
		plot_channels = pt
		### JCALERT! Do the test pt['Strength']='Weights' here
		key = ('Weights',sheet.name,projection.name,view.view_info['x'],view.view_info['y'])
		plot_channels['Strength'] = key
		plot_list.append(make_plot(plot_channels,src_sheet.sheet_view_dict,
                                      src_sheet.density,src_sheet.bounds,pt['Normalize'],self.situate))

        return plot_list

    def _generate_coords(self):
        """
        Evenly space out the units within the sheet bounding box, so
        that it doesn't matter which corner the measurements start
        from.  A 4 unit grid needs 5 segments.  List is in left-to-right,
        from top-to-bottom.
        """
        def rev(x): y = x; y.reverse(); return y

        aarect = self._sim_ep.bounds.aarect()
        (l,b,r,t) = aarect.lbrt()
        x = float(r - l)
        y = float(t - b)
        x_step = x / (int(x * self.density) + 1)
        y_step = y / (int(y * self.density) + 1)
        l = l + x_step
        b = b + y_step
        coords = []
        self.shape = (int(x * self.density), int(y * self.density))
        for j in rev(range(self.shape[1])):
            for i in range(self.shape[0]):
                coords.append((x_step*i + l, y_step*j + b))

        return coords

    def do_plot_cmd(self):
        coords = self._generate_coords()

        full_unitview_list = [self._sim_ep.unit_view(x,y) for (x,y) in coords]

	### JCALERT! The use of chain and nested list here and in
        ### connectionfield.py (unit_view) can be spared or made simpler.

        self.view_list = [view for view in chain(*full_unitview_list)
                         if view.projection.name == self.weight_name]

    ### JCALERT ! for the moment this function is re-implemented only for ProjectionGroup
    ### because we do not want the plots to be sorted according to their src_name in this case
    def plots(self):
        """
        Generate the bitmap lists.
        """
        bitmap_list = []

	self.debug('Dynamic plotgroup')
	self.all_plots = flatten(self.plot_list()) + self.added_list
	self.debug('all_plots = ' + str(self.all_plots))

        generated_bitmap_list = [each for each in self.all_plots if each !=None]
        return generated_bitmap_list

<|endoftext|>


<commit_before>"""
PlotGroupTemplate class, and global repository of such objects.

These classes allow users to specify different types of plots in a way
that is independent of particular models or Sheets.

$Id$
"""
__version__='$Revision$'

from topo.base.topoobject import TopoObject
from topo.misc.keyedlist import KeyedList
from topo.base.parameter import Parameter

class PlotGroupTemplate(TopoObject):
    """
    Class specifying how to construct a PlotGroup from the objects in a Simulator.

    A PlotGroupTemplate is a data structure that specifies how to
    construct a set of related plots, when later given a set of Sheets
    in a Simulator.  The template can be modified however the user
    wishes, allowing the user to control what information is shown in
    plots, how the data is displayed, and so on.  A single template is
    sufficient for any model, because the template does not include
    any information about specific Sheets.  Thus the templates can be
    modified whenever the user desires, but do not *usually* need to
    be modified.
    """

    command = Parameter(None)

    def __init__(self, plot_templates=None, **params):
        """
        A PlotGroupTemplate is constructed from a name, an (optional)
        command that the user specifies should be called before using the
        PlotGroupTemplate, and a plot_templates list.  The plot_templates
        list should contain tuples (plot_name, plot_template).  Each
        plot_template is a dictionary of (name, value) pairs, where each
        name specifies a plotting channel (such as Hue or Confidence), and
        the value is the name of a SheetView (such as Activity or
        OrientationPreference).  Current channels include Strength,
        Hue, and Confidence, but others will be added in the future
        such as Red, Green, Blue, Outline, etc.

        For instance, one could define an Orientation-colored Activity
        plot as:

        pgt.plot_templates['Activity'] =
          PlotGroupTemplate(name='Activity', command='measure_activity()',
                            plot_templates=[('Activity',
                                             {'Strength'   : 'Activity',
                                              'Hue'        : 'OrientationPreference',
                                              'Confidence' : None})])

        This specifies that there will be up to one Plot named Activity in
        the final PlotGroup per Sheet, although there could be no plots at
        all if no Sheet has a SheetView named Activity.  The Plot will be
        colored by OrientationPreference if such a SheetView exists, and
        the value channel will be determined by the SheetView Activity.

        Here's a more complicated example specifying two different plots
        in the same PlotGroup:

          PlotGroupTemplate(name='Orientation Preference', command = 'measure_or_pref()',
                            plot_templates=[('Orientation Preference',
                                             {'Strength'   : None,
                                              'Hue'        : 'OrientationPreference',
                                              'Confidence' : None}),
                                            ('Orientation Selectivity',
                                             {'Strength'   : 'OrientationSelectivity',
                                              'Hue'        : None,
                                              'Confidence' : None})])

        Here the PlotGroup will contain up to two Plots per Sheet,
        depending on which Sheets have OrientationPreference and
        OrientationSelectivity.
        """

        super(PlotGroupTemplate,self).__init__(**params)
        ### JABALERT: Why would plot_templates ever be None?
        if not plot_templates:
            self.plot_templates = KeyedList()
        else:
            self.plot_templates = KeyedList(plot_templates)

###############################################################################
# Specific PlotGroupTemplates are stored in this repository,
# to which users can add their own as needed
plot_templates = {} # JABHACKALERT! What is this for?
plotgroup_templates = KeyedList()

###############################################################################
# Sample plots; users can override any of these as necessary
#
# JABALERT: Should eventually remove anything mentioning OrientationPreference
# or OrientationSelectivity from here, and instead set those up in
# measure_or_pref or somewhere like that.  That way, there will be no special
# treatment of any particular input feature.

# JABALERT: This interface needs some cleanup to make it easier to use.
# For instance, we can implement an add_plot_template function,
# accepting a single plot and adding it to a PlotGroupTemplate (which
# is created the first time it is needed).

pgt = PlotGroupTemplate(name='Activity',
			command='measure_activity()',
			plot_templates= [('Activity',
					  {'Strength'   : 'Activity',
					   'Hue'        : 'OrientationPreference',
					   'Confidence' :  None,
					   'Normalize'  : False})])
plotgroup_templates[pgt.name] = pgt

pgt = PlotGroupTemplate(name='Unit Weights',
                        command='pass',
			plot_templates= [('Unit Weights',
					  {'Strength'   : 'Weights',
					   'Hue'        : 'OrientationPreference',
					   'Confidence' : None,
					   'Normalize'  : True})])
plotgroup_templates[pgt.name] = pgt

### JCALERT: I will remove Density and Projection_name at some point.
### Also implement the test for 'Weights' in PlotGroup.
pgt = PlotGroupTemplate(name='Projection',
                        command='pass',
			plot_templates=[('Projection',
					 {'Strength'      : 'Weights',
					  'Hue'           : 'OrientationPreference',
					  'Confidence'    : None,
                                          'Normalize'       : True,
                                          'Density'         : 25,
                                          'Projection_name' : 'None'})])
plotgroup_templates[pgt.name] = pgt

pgt = PlotGroupTemplate(name='Orientation Preference',
                        command = 'measure_or_pref()',
			plot_templates= [('Orientation Preference',
                                          {'Strength'   : None,
                                           'Hue'        : 'OrientationPreference',
                                           'Confidence' : None}),
                                         ('Orientation Preference&Selectivity',
                                          {'Strength'   : None,
                                           'Hue'        : 'OrientationPreference',
                                           'Confidence' : 'OrientationSelectivity'}),
                                         ('Orientation Selectivity',
                                          {'Strength'   : 'OrientationSelectivity',
                                           'Hue'        : None,
                                           'Confidence' : None})])
plotgroup_templates[pgt.name] = pgt

### JCALERT! Temporary template used for testing RGBPlot. To do that, delete '_Blue' in this
### PlotGroupTemplate, and then it will over-write the othe 'Activity' plotgrouptemplate.
### The activity panel will then use this template (Blue Activity)

pgt = PlotGroupTemplate(name='Activity',
			command='measure_activity()',
			plot_templates= [('Activity_Blue',
					  {'Red'   : 'OrientationPreference',
					   'Green' : 'OrientationPreference',
					   'Blue'  : 'Activity',
					   'Normalize'  : False})])
plotgroup_templates[pgt.name] = pgt
<commit_msg>Cleaned up templates.py from unused part of the code.<commit_after>"""
PlotGroupTemplate class, and global repository of such objects.

These classes allow users to specify different types of plots in a way
that is independent of particular models or Sheets.

$Id$
"""
__version__='$Revision$'

from topo.base.topoobject import TopoObject
from topo.misc.keyedlist import KeyedList
from topo.base.parameter import Parameter

class PlotGroupTemplate(TopoObject):
    """
    Class specifying how to construct a PlotGroup from the objects in a Simulator.

    A PlotGroupTemplate is a data structure that specifies how to
    construct a set of related plots, when later given a set of Sheets
    in a Simulator.  The template can be modified however the user
    wishes, allowing the user to control what information is shown in
    plots, how the data is displayed, and so on.  A single template is
    sufficient for any model, because the template does not include
    any information about specific Sheets.  Thus the templates can be
    modified whenever the user desires, but do not *usually* need to
    be modified.
    """

    command = Parameter(None)

    def __init__(self, plot_templates=None, **params):
        """
        A PlotGroupTemplate is constructed from a name, an (optional)
        command that the user specifies should be called before using the
        PlotGroupTemplate, and a plot_templates list.  The plot_templates
        list should contain tuples (plot_name, plot_template).  Each
        plot_template is a dictionary of (name, value) pairs, where each
        name specifies a plotting channel (such as Hue or Confidence), and
        the value is the name of a SheetView (such as Activity or
        OrientationPreference).  Current channels include Strength,
        Hue, and Confidence, but others will be added in the future
        such as Red, Green, Blue, Outline, etc.

        For instance, one could define an Orientation-colored Activity
        plot as:

        pgt.plot_templates['Activity'] =
          PlotGroupTemplate(name='Activity', command='measure_activity()',
                            plot_templates=[('Activity',
                                             {'Strength'   : 'Activity',
                                              'Hue'        : 'OrientationPreference',
                                              'Confidence' : None})])

        This specifies that there will be up to one Plot named Activity in
        the final PlotGroup per Sheet, although there could be no plots at
        all if no Sheet has a SheetView named Activity.  The Plot will be
        colored by OrientationPreference if such a SheetView exists, and
        the value channel will be determined by the SheetView Activity.

        Here's a more complicated example specifying two different plots
        in the same PlotGroup:

          PlotGroupTemplate(name='Orientation Preference', command = 'measure_or_pref()',
                            plot_templates=[('Orientation Preference',
                                             {'Strength'   : None,
                                              'Hue'        : 'OrientationPreference',
                                              'Confidence' : None}),
                                            ('Orientation Selectivity',
                                             {'Strength'   : 'OrientationSelectivity',
                                              'Hue'        : None,
                                              'Confidence' : None})])

        Here the PlotGroup will contain up to two Plots per Sheet,
        depending on which Sheets have OrientationPreference and
        OrientationSelectivity.
        """

        super(PlotGroupTemplate,self).__init__(**params)

	self.plot_templates = KeyedList(plot_templates)

###############################################################################
# Specific PlotGroupTemplates are stored in this repository,
# to which users can add their own as needed
plotgroup_templates = KeyedList()

###############################################################################
# Sample plots; users can override any of these as necessary
#
# JABALERT: Should eventually remove anything mentioning OrientationPreference
# or OrientationSelectivity from here, and instead set those up in
# measure_or_pref or somewhere like that.  That way, there will be no special
# treatment of any particular input feature.

# JABALERT: This interface needs some cleanup to make it easier to use.
# For instance, we can implement an add_plot_template function,
# accepting a single plot and adding it to a PlotGroupTemplate (which
# is created the first time it is needed).

pgt = PlotGroupTemplate(name='Activity',
			command='measure_activity()',
			plot_templates= [('Activity',
					  {'Strength'   : 'Activity',
					   'Hue'        : 'OrientationPreference',
					   'Confidence' :  None,
					   'Normalize'  : False})])
plotgroup_templates[pgt.name] = pgt

pgt = PlotGroupTemplate(name='Unit Weights',
                        command='pass',
			plot_templates= [('Unit Weights',
					  {'Strength'   : 'Weights',
					   'Hue'        : 'OrientationPreference',
					   'Confidence' : None,
					   'Normalize'  : True})])
plotgroup_templates[pgt.name] = pgt

### JCALERT: I will remove Density and Projection_name at some point.
### Also implement the test for 'Weights' in PlotGroup.
pgt = PlotGroupTemplate(name='Projection',
                        command='pass',
			plot_templates=[('Projection',
					 {'Strength'      : 'Weights',
					  'Hue'           : 'OrientationPreference',
					  'Confidence'    : None,
                                          'Normalize'       : True,
                                          'Density'         : 25,
                                          'Projection_name' : 'None'})])
plotgroup_templates[pgt.name] = pgt

pgt = PlotGroupTemplate(name='Orientation Preference',
                        command = 'measure_or_pref()',
			plot_templates= [('Orientation Preference',
                                          {'Strength'   : None,
                                           'Hue'        : 'OrientationPreference',
                                           'Confidence' : None}),
                                         ('Orientation Preference&Selectivity',
                                          {'Strength'   : None,
                                           'Hue'        : 'OrientationPreference',
                                           'Confidence' : 'OrientationSelectivity'}),
                                         ('Orientation Selectivity',
                                          {'Strength'   : 'OrientationSelectivity',
                                           'Hue'        : None,
                                           'Confidence' : None})])
plotgroup_templates[pgt.name] = pgt

### JCALERT! Temporary template used for testing RGBPlot. To do that, delete '_Blue' in this
### PlotGroupTemplate, and then it will over-write the othe 'Activity' plotgrouptemplate.
### The activity panel will then use this template (Blue Activity)

pgt = PlotGroupTemplate(name='Activity',
			command='measure_activity()',
			plot_templates= [('Activity_Blue',
					  {'Red'   : 'OrientationPreference',
					   'Green' : 'OrientationPreference',
					   'Blue'  : 'Activity',
					   'Normalize'  : False})])
plotgroup_templates[pgt.name] = pgt
<|endoftext|>


<commit_before>from __future__ import division

import math
import random

import torch

from .utils import RandomShuffler
from .batch import Batch
from .dataset import Dataset

class Iterator(object):
    """Defines an iterator that loads batches of data from a Dataset.

    Attributes:
        dataset: The Dataset object to load Examples from.
        batch_size: Batch size.
        batch_size_fn: Function of three arguments (new example to add, current
            count of examples in the batch, and current effective batch size)
            that returns the new effective batch size resulting from adding
            that example to a batch. This is useful for dynamic batching, where
            this function would add to the current effective batch size the
            number of tokens in the new example.
        sort_key: A key to use for sorting examples in order to batch together
            examples with similar lengths and minimize padding. The sort_key
            provided to the Iterator constructor overrides the sort_key
            attribute of the Dataset, or defers to it if None.
        train: Whether the iterator represents a train set.
        repeat: Whether to repeat the iterator for multiple epochs.
        shuffle: Whether to shuffle examples between epochs.
        sort: Whether to sort examples according to self.sort_key.
            Note that repeat, shuffle, and sort default to train, train, and
            (not train).
        sort_within_batch: Whether to sort (in descending order according to
            self.sort_key) within each batch. If None, defaults to self.sort.
            If self.sort is True and this is False, the batch is left in the
            original (ascending) sorted order.
        device: Device to create batches on. Use -1 for CPU and None for the
            currently active GPU device.
    """

    def __init__(self, dataset, batch_size, sort_key=None, device=None,
                 batch_size_fn=None, train=True,
                 repeat=None, shuffle=None, sort=None,
                 sort_within_batch=None):
        self.batch_size, self.train, self.dataset = batch_size, train, dataset
        self.batch_size_fn = batch_size_fn
        self.iterations = 0
        self.repeat = train if repeat is None else repeat
        self.shuffle = train if shuffle is None else shuffle
        self.sort = not train if sort is None else sort
        if sort_within_batch is None:
            self.sort_within_batch = self.sort
        else:
            self.sort_within_batch = sort_within_batch
        if sort_key is None:
            self.sort_key = dataset.sort_key
        else:
            self.sort_key = sort_key
        self.device = device
        if not torch.cuda.is_available() and self.device is None:
            self.device = -1

        self.random_shuffler = RandomShuffler()

        # For state loading/saving only
        self._iterations_this_epoch = 0
        self._random_state_this_epoch = None
        self._restored_from_state = False

    @classmethod
    def splits(cls, datasets, batch_sizes=None, **kwargs):
        """Create Iterator objects for multiple splits of a dataset.

        Arguments:
            datasets: Tuple of Dataset objects corresponding to the splits. The
                first such object should be the train set.
            batch_sizes: Tuple of batch sizes to use for the different splits,
                or None to use the same batch_size for all splits.
            Remaining keyword arguments: Passed to the constructor of the
                iterator class being used.
        """
        if batch_sizes is None:
            batch_sizes = [kwargs.pop('batch_size')] * len(datasets)
        ret = []
        for i in range(len(datasets)):
            train = i == 0
            ret.append(cls(
                datasets[i], batch_size=batch_sizes[i], train=train, **kwargs))
        return tuple(ret)

    def data(self):
        """Return the examples in the dataset in order, sorted, or shuffled."""
        if self.sort:
            xs = sorted(self.dataset, key=self.sort_key)
        elif self.shuffle:
            xs = [self.dataset[i] for i in self.random_shuffler(range(len(self.dataset)))]
        else:
            xs = self.dataset
        return xs

    def init_epoch(self):
        """Set up the batch generator for a new epoch."""

        if self._restored_from_state:
            self.random_shuffler.random_state = self._random_state_this_epoch
        else:
            self._random_state_this_epoch = self.random_shuffler.random_state

        self.create_batches()

        if self._restored_from_state:
            self._restored_from_state = False
        else:
            self._iterations_this_epoch = 0

        if not self.repeat:
            self.iterations = 0

    def create_batches(self):
        self.batches = batch(self.data(), self.batch_size, self.batch_size_fn)

    @property
    def epoch(self):
        return self.iterations / len(self)

    def __len__(self):
        if self.batch_size_fn is not None:
            raise NotImplementedError
        return math.ceil(len(self.dataset) / self.batch_size)

    def __iter__(self):
        while True:
            self.init_epoch()
            for idx, minibatch in enumerate(self.batches):
                # fast-forward if loaded from state
                if self._iterations_this_epoch > idx:
                    continue
                self.iterations += 1
                self._iterations_this_epoch += 1
                if self.sort_within_batch:
                    # NOTE: `rnn.pack_padded_sequence` requires that a minibatch
                    # be sorted by decreasing order, which requires reversing
                    # relative to typical sort keys
                    if self.sort:
                        minibatch.reverse()
                    else:
                        minibatch.sort(key=self.sort_key, reverse=True)
                yield Batch(minibatch, self.dataset, self.device,
                            self.train)
            if not self.repeat:
                return

    def state_dict(self):
        return {
            "iterations": self.iterations,
            "iterations_this_epoch": self._iterations_this_epoch,
            "random_state_this_epoch": self._random_state_this_epoch}

    def load_state_dict(self, state_dict):
        self.iterations = state_dict["iterations"]
        self._iterations_this_epoch = state_dict["iterations_this_epoch"]
        self._random_state_this_epoch = state_dict["random_state_this_epoch"]
        self._restored_from_state = True

class BPTTIterator(Iterator):
    """Defines an iterator for language modeling tasks that use BPTT.

    Provides contiguous streams of examples together with targets that are
    one timestep further forward, for language modeling training with
    backpropagation through time (BPTT). Expects a Dataset with a single
    example and a single field called 'text' and produces Batches with text and
    target attributes.

    Attributes:
        dataset: The Dataset object to load Examples from.
        batch_size: Batch size.
        bptt_len: Length of sequences for backpropagation through time.
        sort_key: A key to use for sorting examples in order to batch together
            examples with similar lengths and minimize padding. The sort_key
            provided to the Iterator constructor overrides the sort_key
            attribute of the Dataset, or defers to it if None.
        train: Whether the iterator represents a train set.
        repeat: Whether to repeat the iterator for multiple epochs.
        shuffle: Whether to shuffle examples between epochs.
        sort: Whether to sort examples according to self.sort_key.
            Note that repeat, shuffle, and sort default to train, train, and
            (not train).
        device: Device to create batches on. Use -1 for CPU and None for the
            currently active GPU device.
    """

    def __init__(self, dataset, batch_size, bptt_len, **kwargs):
        self.bptt_len = bptt_len
        super(BPTTIterator, self).__init__(dataset, batch_size, **kwargs)

    def __len__(self):
        return math.ceil((len(self.dataset[0].text) / self.batch_size - 1) /
                         self.bptt_len)

    def __iter__(self):
        text = self.dataset[0].text
        TEXT = self.dataset.fields['text']
        TEXT.eos_token = None
        text = text + ([TEXT.pad_token] * int(math.ceil(len(text) / self.batch_size) *
                                              self.batch_size - len(text)))
        data = TEXT.numericalize(
            [text], device=self.device, train=self.train)
        data = data.view(self.batch_size, -1).t().contiguous()
        dataset = Dataset(examples=self.dataset.examples, fields=[
            ('text', TEXT), ('target', TEXT)])
        while True:
            for i in range(0, len(self) * self.bptt_len, self.bptt_len):
                seq_len = min(self.bptt_len, len(data) - i - 1)
                yield Batch.fromvars(
                    dataset, self.batch_size, train=self.train,
                    text=data[i:i + seq_len],
                    target=data[i + 1:i + 1 + seq_len])
            if not self.repeat:
                raise StopIteration

class BucketIterator(Iterator):
    """Defines an iterator that batches examples of similar lengths together.

    Minimizes amount of padding needed while producing freshly shuffled
    batches for each new epoch. See pool for the bucketing procedure used.
    """

    def create_batches(self):
        if self.sort:
            self.batches = batch(self.data(), self.batch_size,
                                 self.batch_size_fn)
        else:
            self.batches = pool(self.data(), self.batch_size,
                                self.sort_key, self.batch_size_fn,
                                random_shuffler=self.random_shuffler)

def batch(data, batch_size, batch_size_fn=None):
    """Yield elements from data in chunks of batch_size."""
    if batch_size_fn is None:
        def batch_size_fn(new, count, sofar):
            return count
    minibatch, size_so_far = [], 0
    for ex in data:
        minibatch.append(ex)
        size_so_far = batch_size_fn(ex, len(minibatch), size_so_far)
        if size_so_far == batch_size:
            yield minibatch
            minibatch, size_so_far = [], 0
        elif size_so_far > batch_size:
            yield minibatch[:-1]
            minibatch, size_so_far = minibatch[-1:], batch_size_fn(ex, 1, 0)
    if minibatch:
        yield minibatch

def pool(data, batch_size, key, batch_size_fn=lambda new, count, sofar: count,
         random_shuffler=None):
    """Sort within buckets, then batch, then shuffle batches.

    Partitions data into chunks of size 100*batch_size, sorts examples within
    each chunk using sort_key, then batch these examples and shuffle the
    batches.
    """
    if random_shuffler is None:
        random_shuffler = random.shuffle
    for p in batch(data, batch_size * 100, batch_size_fn):
        p_batch = batch(sorted(p, key=key), batch_size, batch_size_fn)
        for b in random_shuffler(list(p_batch)):
            yield b
<commit_msg>Fix deprecated StopIteration, increment iterations in BPTTIterator, make epoch() return int (#259)<commit_after>from __future__ import division

import math
import random

import torch

from .utils import RandomShuffler
from .batch import Batch
from .dataset import Dataset

class Iterator(object):
    """Defines an iterator that loads batches of data from a Dataset.

    Attributes:
        dataset: The Dataset object to load Examples from.
        batch_size: Batch size.
        batch_size_fn: Function of three arguments (new example to add, current
            count of examples in the batch, and current effective batch size)
            that returns the new effective batch size resulting from adding
            that example to a batch. This is useful for dynamic batching, where
            this function would add to the current effective batch size the
            number of tokens in the new example.
        sort_key: A key to use for sorting examples in order to batch together
            examples with similar lengths and minimize padding. The sort_key
            provided to the Iterator constructor overrides the sort_key
            attribute of the Dataset, or defers to it if None.
        train: Whether the iterator represents a train set.
        repeat: Whether to repeat the iterator for multiple epochs.
        shuffle: Whether to shuffle examples between epochs.
        sort: Whether to sort examples according to self.sort_key.
            Note that repeat, shuffle, and sort default to train, train, and
            (not train).
        sort_within_batch: Whether to sort (in descending order according to
            self.sort_key) within each batch. If None, defaults to self.sort.
            If self.sort is True and this is False, the batch is left in the
            original (ascending) sorted order.
        device: Device to create batches on. Use -1 for CPU and None for the
            currently active GPU device.
    """

    def __init__(self, dataset, batch_size, sort_key=None, device=None,
                 batch_size_fn=None, train=True,
                 repeat=None, shuffle=None, sort=None,
                 sort_within_batch=None):
        self.batch_size, self.train, self.dataset = batch_size, train, dataset
        self.batch_size_fn = batch_size_fn
        self.iterations = 0
        self.repeat = train if repeat is None else repeat
        self.shuffle = train if shuffle is None else shuffle
        self.sort = not train if sort is None else sort
        if sort_within_batch is None:
            self.sort_within_batch = self.sort
        else:
            self.sort_within_batch = sort_within_batch
        if sort_key is None:
            self.sort_key = dataset.sort_key
        else:
            self.sort_key = sort_key
        self.device = device
        if not torch.cuda.is_available() and self.device is None:
            self.device = -1

        self.random_shuffler = RandomShuffler()

        # For state loading/saving only
        self._iterations_this_epoch = 0
        self._random_state_this_epoch = None
        self._restored_from_state = False

    @classmethod
    def splits(cls, datasets, batch_sizes=None, **kwargs):
        """Create Iterator objects for multiple splits of a dataset.

        Arguments:
            datasets: Tuple of Dataset objects corresponding to the splits. The
                first such object should be the train set.
            batch_sizes: Tuple of batch sizes to use for the different splits,
                or None to use the same batch_size for all splits.
            Remaining keyword arguments: Passed to the constructor of the
                iterator class being used.
        """
        if batch_sizes is None:
            batch_sizes = [kwargs.pop('batch_size')] * len(datasets)
        ret = []
        for i in range(len(datasets)):
            train = i == 0
            ret.append(cls(
                datasets[i], batch_size=batch_sizes[i], train=train, **kwargs))
        return tuple(ret)

    def data(self):
        """Return the examples in the dataset in order, sorted, or shuffled."""
        if self.sort:
            xs = sorted(self.dataset, key=self.sort_key)
        elif self.shuffle:
            xs = [self.dataset[i] for i in self.random_shuffler(range(len(self.dataset)))]
        else:
            xs = self.dataset
        return xs

    def init_epoch(self):
        """Set up the batch generator for a new epoch."""

        if self._restored_from_state:
            self.random_shuffler.random_state = self._random_state_this_epoch
        else:
            self._random_state_this_epoch = self.random_shuffler.random_state

        self.create_batches()

        if self._restored_from_state:
            self._restored_from_state = False
        else:
            self._iterations_this_epoch = 0

        if not self.repeat:
            self.iterations = 0

    def create_batches(self):
        self.batches = batch(self.data(), self.batch_size, self.batch_size_fn)

    @property
    def epoch(self):
        return math.floor(self.iterations / len(self))

    def __len__(self):
        if self.batch_size_fn is not None:
            raise NotImplementedError
        return math.ceil(len(self.dataset) / self.batch_size)

    def __iter__(self):
        while True:
            self.init_epoch()
            for idx, minibatch in enumerate(self.batches):
                # fast-forward if loaded from state
                if self._iterations_this_epoch > idx:
                    continue
                self.iterations += 1
                self._iterations_this_epoch += 1
                if self.sort_within_batch:
                    # NOTE: `rnn.pack_padded_sequence` requires that a minibatch
                    # be sorted by decreasing order, which requires reversing
                    # relative to typical sort keys
                    if self.sort:
                        minibatch.reverse()
                    else:
                        minibatch.sort(key=self.sort_key, reverse=True)
                yield Batch(minibatch, self.dataset, self.device,
                            self.train)
            if not self.repeat:
                return

    def state_dict(self):
        return {
            "iterations": self.iterations,
            "iterations_this_epoch": self._iterations_this_epoch,
            "random_state_this_epoch": self._random_state_this_epoch}

    def load_state_dict(self, state_dict):
        self.iterations = state_dict["iterations"]
        self._iterations_this_epoch = state_dict["iterations_this_epoch"]
        self._random_state_this_epoch = state_dict["random_state_this_epoch"]
        self._restored_from_state = True

class BPTTIterator(Iterator):
    """Defines an iterator for language modeling tasks that use BPTT.

    Provides contiguous streams of examples together with targets that are
    one timestep further forward, for language modeling training with
    backpropagation through time (BPTT). Expects a Dataset with a single
    example and a single field called 'text' and produces Batches with text and
    target attributes.

    Attributes:
        dataset: The Dataset object to load Examples from.
        batch_size: Batch size.
        bptt_len: Length of sequences for backpropagation through time.
        sort_key: A key to use for sorting examples in order to batch together
            examples with similar lengths and minimize padding. The sort_key
            provided to the Iterator constructor overrides the sort_key
            attribute of the Dataset, or defers to it if None.
        train: Whether the iterator represents a train set.
        repeat: Whether to repeat the iterator for multiple epochs.
        shuffle: Whether to shuffle examples between epochs.
        sort: Whether to sort examples according to self.sort_key.
            Note that repeat, shuffle, and sort default to train, train, and
            (not train).
        device: Device to create batches on. Use -1 for CPU and None for the
            currently active GPU device.
    """

    def __init__(self, dataset, batch_size, bptt_len, **kwargs):
        self.bptt_len = bptt_len
        super(BPTTIterator, self).__init__(dataset, batch_size, **kwargs)

    def __len__(self):
        return math.ceil((len(self.dataset[0].text) / self.batch_size - 1) /
                         self.bptt_len)

    def __iter__(self):
        text = self.dataset[0].text
        TEXT = self.dataset.fields['text']
        TEXT.eos_token = None
        text = text + ([TEXT.pad_token] * int(math.ceil(len(text) / self.batch_size) *
                                              self.batch_size - len(text)))
        data = TEXT.numericalize(
            [text], device=self.device, train=self.train)
        data = data.view(self.batch_size, -1).t().contiguous()
        dataset = Dataset(examples=self.dataset.examples, fields=[
            ('text', TEXT), ('target', TEXT)])
        while True:
            for i in range(0, len(self) * self.bptt_len, self.bptt_len):
                self.iterations += 1
                seq_len = min(self.bptt_len, len(data) - i - 1)
                yield Batch.fromvars(
                    dataset, self.batch_size, train=self.train,
                    text=data[i:i + seq_len],
                    target=data[i + 1:i + 1 + seq_len])
            if not self.repeat:
                return

class BucketIterator(Iterator):
    """Defines an iterator that batches examples of similar lengths together.

    Minimizes amount of padding needed while producing freshly shuffled
    batches for each new epoch. See pool for the bucketing procedure used.
    """

    def create_batches(self):
        if self.sort:
            self.batches = batch(self.data(), self.batch_size,
                                 self.batch_size_fn)
        else:
            self.batches = pool(self.data(), self.batch_size,
                                self.sort_key, self.batch_size_fn,
                                random_shuffler=self.random_shuffler)

def batch(data, batch_size, batch_size_fn=None):
    """Yield elements from data in chunks of batch_size."""
    if batch_size_fn is None:
        def batch_size_fn(new, count, sofar):
            return count
    minibatch, size_so_far = [], 0
    for ex in data:
        minibatch.append(ex)
        size_so_far = batch_size_fn(ex, len(minibatch), size_so_far)
        if size_so_far == batch_size:
            yield minibatch
            minibatch, size_so_far = [], 0
        elif size_so_far > batch_size:
            yield minibatch[:-1]
            minibatch, size_so_far = minibatch[-1:], batch_size_fn(ex, 1, 0)
    if minibatch:
        yield minibatch

def pool(data, batch_size, key, batch_size_fn=lambda new, count, sofar: count,
         random_shuffler=None):
    """Sort within buckets, then batch, then shuffle batches.

    Partitions data into chunks of size 100*batch_size, sorts examples within
    each chunk using sort_key, then batch these examples and shuffle the
    batches.
    """
    if random_shuffler is None:
        random_shuffler = random.shuffle
    for p in batch(data, batch_size * 100, batch_size_fn):
        p_batch = batch(sorted(p, key=key), batch_size, batch_size_fn)
        for b in random_shuffler(list(p_batch)):
            yield b
<|endoftext|>


<commit_before>"""
Test calling a function that hits a signal set to auto-restart, make sure the call completes.
"""

import unittest2
import lldb
import lldbutil
from lldbtest import *

class ExprCommandThatRestartsTestCase(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)

        self.main_source = "lotta-signals.c"
        self.main_source_spec = lldb.SBFileSpec (self.main_source)

    @skipUnlessDarwin
    @dsym_test
    @skipIfDarwin # llvm.org/pr19246: intermittent failure
    def test_with_dsym(self):
        """Test calling std::String member function."""
        self.buildDsym()
        self.call_function()

    @dwarf_test
    @skipIfFreeBSD # llvm.org/pr19246: intermittent failure
    @skipIfDarwin # llvm.org/pr19246: intermittent failure
    @skipIfWindows # Test relies on signals, unsupported on Windows
    def test_with_dwarf(self):
        """Test calling std::String member function."""
        self.buildDwarf()
        self.call_function()

    def check_after_call (self, num_sigchld):
        after_call = self.sigchld_no.GetValueAsSigned(-1)
        self.assertTrue (after_call - self.start_sigchld_no == num_sigchld, "Really got %d SIGCHLD signals through the call."%(num_sigchld))
        self.start_sigchld_no = after_call

        # Check that we are back where we were before:
        frame = self.thread.GetFrameAtIndex(0)
        self.assertTrue (self.orig_frame_pc == frame.GetPC(), "Restored the zeroth frame correctly")

    def call_function(self):
        """Test calling function that hits a signal and restarts."""
        exe_name = "a.out"
        exe = os.path.join(os.getcwd(), exe_name)

        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)
        empty = lldb.SBFileSpec()
        breakpoint = target.BreakpointCreateBySourceRegex('Stop here in main.',self.main_source_spec)
        self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT)

        # Launch the process, and do not stop at the entry point.
        process = target.LaunchSimple (None, None, self.get_process_working_directory())

        self.assertTrue(process, PROCESS_IS_VALID)

        # Frame #0 should be at our breakpoint.
        threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint)

        self.assertTrue(len(threads) == 1)
        self.thread = threads[0]

        # Make sure the SIGCHLD behavior is pass/no-stop/no-notify:
        return_obj = lldb.SBCommandReturnObject()
        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 0", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop")

        # The sigchld_no variable should be 0 at this point.
        self.sigchld_no = target.FindFirstGlobalVariable("sigchld_no")
        self.assertTrue (self.sigchld_no.IsValid(), "Got a value for sigchld_no")

        self.start_sigchld_no = self.sigchld_no.GetValueAsSigned (-1)
        self.assertTrue (self.start_sigchld_no != -1, "Got an actual value for sigchld_no")

        options = lldb.SBExpressionOptions()
        options.SetUnwindOnError(True)

        frame = self.thread.GetFrameAtIndex(0)
        # Store away the PC to check that the functions unwind to the right place after calls
        self.orig_frame_pc = frame.GetPC()

        num_sigchld = 30
        value = frame.EvaluateExpression ("call_me (%d)"%(num_sigchld), options)
        self.assertTrue (value.IsValid())
        self.assertTrue (value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)

        self.check_after_call(num_sigchld)

        # Okay, now try with a breakpoint in the called code in the case where
        # we are ignoring breakpoint hits.
        handler_bkpt = target.BreakpointCreateBySourceRegex("Got sigchld %d.", self.main_source_spec)
        self.assertTrue (handler_bkpt.GetNumLocations() > 0)
        options.SetIgnoreBreakpoints(True)
        options.SetUnwindOnError(True)

        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)

        self.assertTrue (value.IsValid() and value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
        self.check_after_call(num_sigchld)

        # Now set the signal to print but not stop and make sure that calling still works:
        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify")

        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)

        self.assertTrue (value.IsValid() and value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
        self.check_after_call(num_sigchld)

        # Now set this unwind on error to false, and make sure that we still complete the call:
        options.SetUnwindOnError(False)
        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)

        self.assertTrue (value.IsValid() and value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
        self.check_after_call(num_sigchld)

        # Okay, now set UnwindOnError to true, and then make the signal behavior to stop
        # and see that now we do stop at the signal point:

        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 1 -p 1 -n 1", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, stop, notify")

        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)
        self.assertTrue (value.IsValid() and value.GetError().Success() == False)

        # Set signal handling back to no-stop, and continue and we should end up back in out starting frame:
        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify")

        error = process.Continue()
        self.assertTrue (error.Success(), "Continuing after stopping for signal succeeds.")

        frame = self.thread.GetFrameAtIndex(0)
        self.assertTrue (frame.GetPC() == self.orig_frame_pc, "Continuing returned to the place we started.")

if __name__ == '__main__':
    import atexit
    lldb.SBDebugger.Initialize()
    atexit.register(lambda: lldb.SBDebugger.Terminate())
    unittest2.main()
<commit_msg>Increase timeout in TestCallThatRestarts<commit_after>"""
Test calling a function that hits a signal set to auto-restart, make sure the call completes.
"""

import unittest2
import lldb
import lldbutil
from lldbtest import *

class ExprCommandThatRestartsTestCase(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)

        self.main_source = "lotta-signals.c"
        self.main_source_spec = lldb.SBFileSpec (self.main_source)

    @skipUnlessDarwin
    @dsym_test
    @skipIfDarwin # llvm.org/pr19246: intermittent failure
    def test_with_dsym(self):
        """Test calling std::String member function."""
        self.buildDsym()
        self.call_function()

    @dwarf_test
    @skipIfFreeBSD # llvm.org/pr19246: intermittent failure
    @skipIfDarwin # llvm.org/pr19246: intermittent failure
    @skipIfWindows # Test relies on signals, unsupported on Windows
    def test_with_dwarf(self):
        """Test calling std::String member function."""
        self.buildDwarf()
        self.call_function()

    def check_after_call (self, num_sigchld):
        after_call = self.sigchld_no.GetValueAsSigned(-1)
        self.assertTrue (after_call - self.start_sigchld_no == num_sigchld, "Really got %d SIGCHLD signals through the call."%(num_sigchld))
        self.start_sigchld_no = after_call

        # Check that we are back where we were before:
        frame = self.thread.GetFrameAtIndex(0)
        self.assertTrue (self.orig_frame_pc == frame.GetPC(), "Restored the zeroth frame correctly")

    def call_function(self):
        """Test calling function that hits a signal and restarts."""
        exe_name = "a.out"
        exe = os.path.join(os.getcwd(), exe_name)

        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)
        empty = lldb.SBFileSpec()
        breakpoint = target.BreakpointCreateBySourceRegex('Stop here in main.',self.main_source_spec)
        self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT)

        # Launch the process, and do not stop at the entry point.
        process = target.LaunchSimple (None, None, self.get_process_working_directory())

        self.assertTrue(process, PROCESS_IS_VALID)

        # Frame #0 should be at our breakpoint.
        threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint)

        self.assertTrue(len(threads) == 1)
        self.thread = threads[0]

        # Make sure the SIGCHLD behavior is pass/no-stop/no-notify:
        return_obj = lldb.SBCommandReturnObject()
        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 0", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop")

        # The sigchld_no variable should be 0 at this point.
        self.sigchld_no = target.FindFirstGlobalVariable("sigchld_no")
        self.assertTrue (self.sigchld_no.IsValid(), "Got a value for sigchld_no")

        self.start_sigchld_no = self.sigchld_no.GetValueAsSigned (-1)
        self.assertTrue (self.start_sigchld_no != -1, "Got an actual value for sigchld_no")

        options = lldb.SBExpressionOptions()
        # processing 30 signals takes a while, increase the expression timeout a bit
        options.SetTimeoutInMicroSeconds(3000000) # 3s
        options.SetUnwindOnError(True)

        frame = self.thread.GetFrameAtIndex(0)
        # Store away the PC to check that the functions unwind to the right place after calls
        self.orig_frame_pc = frame.GetPC()

        num_sigchld = 30
        value = frame.EvaluateExpression ("call_me (%d)"%(num_sigchld), options)
        self.assertTrue (value.IsValid())
        self.assertTrue (value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)

        self.check_after_call(num_sigchld)

        # Okay, now try with a breakpoint in the called code in the case where
        # we are ignoring breakpoint hits.
        handler_bkpt = target.BreakpointCreateBySourceRegex("Got sigchld %d.", self.main_source_spec)
        self.assertTrue (handler_bkpt.GetNumLocations() > 0)
        options.SetIgnoreBreakpoints(True)
        options.SetUnwindOnError(True)

        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)

        self.assertTrue (value.IsValid() and value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
        self.check_after_call(num_sigchld)

        # Now set the signal to print but not stop and make sure that calling still works:
        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify")

        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)

        self.assertTrue (value.IsValid() and value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
        self.check_after_call(num_sigchld)

        # Now set this unwind on error to false, and make sure that we still complete the call:
        options.SetUnwindOnError(False)
        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)

        self.assertTrue (value.IsValid() and value.GetError().Success() == True)
        self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
        self.check_after_call(num_sigchld)

        # Okay, now set UnwindOnError to true, and then make the signal behavior to stop
        # and see that now we do stop at the signal point:

        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 1 -p 1 -n 1", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, stop, notify")

        value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)
        self.assertTrue (value.IsValid() and value.GetError().Success() == False)

        # Set signal handling back to no-stop, and continue and we should end up back in out starting frame:
        self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj)
        self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify")

        error = process.Continue()
        self.assertTrue (error.Success(), "Continuing after stopping for signal succeeds.")

        frame = self.thread.GetFrameAtIndex(0)
        self.assertTrue (frame.GetPC() == self.orig_frame_pc, "Continuing returned to the place we started.")

if __name__ == '__main__':
    import atexit
    lldb.SBDebugger.Initialize()
    atexit.register(lambda: lldb.SBDebugger.Terminate())
    unittest2.main()
<|endoftext|>