text:
Thank you for visiting nature.com. You are using a browser version with limited support for CSS. To obtain the best experience, we recommend you use a more up to date browser (or turn off compatibility mode in Internet Explorer). In the meantime, to ensure continued support, we are displaying the site without styles and JavaScript.

# Hitchhiking, collapse, and contingency in phage infections of migrating bacterial populations

## Abstract

Natural bacterial populations are subjected to constant predation pressure by bacteriophages. Bacteria use a variety of molecular mechanisms to defend themselves from phage predation. However, since phages are nonmotile, perhaps the simplest defense against phage is for bacteria to move faster than phages. In particular, chemotaxis, the active migration of bacteria up attractant gradients, may help the bacteria escape slowly diffusing phages. Here we study phage infection dynamics in migrating bacterial populations driven by chemotaxis through low viscosity agar plates. We find that expanding phage–bacteria populations supports two moving fronts, an outermost bacterial front driven by nutrient uptake and chemotaxis and an inner phage front at which the bacterial population collapses due to phage predation. We show that with increasing adsorption rate and initial phage population, the speed of the moving phage front increases, eventually overtaking the bacterial front and driving the system across a transition from a regime where bacterial front speed exceeds that of the phage front to one where bacteria must evolve phage resistance to survive. Our data support the claim that this process requires phage to hitchhike with moving bacteria. A deterministic model recapitulates the transition under the assumption that phage virulence declines with host growth rate which we confirm experimentally. Finally, near the transition between regimes we observe macroscopic fluctuations in bacterial densities at the phage front. Our work opens a new, spatio-temporal, line of investigation into the eco-evolutionary struggle between bacteria and phage.

## Introduction

In natural environments, including oceans and soils, phages and bacteria interact in a spatially structured context. The spatial structure in these environments spans multiple scales from particles of a few micrometers such as marine snow [1] to large scale microbial populations such as blooms [2]. Despite the ubiquity of spatial structure in these natural environments, our understanding of the dynamics of phage infections is largely based on experiments in well-mixed systems [3,4,5,6,7,8]. For example, decades of studies of phage in chemostats have shed light on the long-term coevolutionary processes in well-mixed conditions [6, 9,10,11].

Less is known, however, about the role of spatial structure on phage–host interactions. The most detailed accounting of phage–host interactions in space is available in the context of plaque formation. Plaque-forming phages interact with a dense, spatially homogeneous host population. However, unlike well-mixed systems, phages in plaques must infect and propagate locally in space. The dynamics of plaque formation have been studied in detail theoretically and experimentally. For example, several studies have examined the expansion rate of a growing plaque as a function of the microscopic properties of the phage–host interaction [12]. A careful theoretical study showed that the plaque expansion dynamics could be understood quantitatively if the latency period of the phage in the host and the role of bacterial crowding in limiting phage diffusion are accounted for [13]. Experiments have shown that the plaque formation process can favor mutant phages that exhibit lower adsorption rates to their host [14]. Experimental evolution for plaque size also resulted in phage strains with reduced infectivity [15]. A related study showed that low productivity phages can exhibit enhanced fitness in direct competition experiments when the environment is spatially structured [16]. A recent study showed that colonies of susceptible bacteria can survive a phage attack if they are of sufficient size to protect growing cells at the interior of the colony [17]. These studies of plaque formation dynamics have revealed how phage attacks a dense, growing, and nonmotile host population and that these conditions typically favor phage of lower infectivity and productivity.

The ability of phage to attack bacteria present in biofilms has also been explored [18, 19]. In biofilms, bacteria are embedded in dense exopolysaccharide matrices which can be degraded by enzymes carried on the capsids of phage [20] and it is known that phage infection can impact biofilm morphology [21]. In biofilms, as in the plaque formation context, bacterial hosts are not motile but instead remain fixed in space. Complementing these experimental efforts are several theoretical attempts to describe spatially structured phage–bacterial interactions [22,23,24].

In nature, bacteria in the planktonic state are often motile and exhibit chemotaxis up gradients of attractant. As a result, host motility is an important and unexplored aspect of phage–bacteria interactions. To our knowledge there is no existing study of the dynamics of phage–host interactions in a situation where the host is actively migrating up a gradient of nutrients. Here, we study the interaction between phages and bacterial populations moving through a porous environment. In our experiments, bacterial populations migrate at rates of several millimeters per hour due to chemotaxis and growth driven by a self-organized nutrient gradient [25, 26]. Since chemotaxis is widespread in many natural habitats shared by bacteria and phages, including oceans [27, 28] and soil [29], we expect the process studied here may be relevant to bacteria–phage interactions in environments where motility and chemotaxis are important.

Here we show that the interplay between chemotaxis and phage predation results in rich spatio-temporal dynamics. In this context, a bacterial front composed of the fastest migrating bacteria, which harbor a hitchhiking phage population, is trailed by a secondary phage front where the bacterial population collapses under predation pressure. The rate of migration of this phage front increases with the size of the initial phage population and the rate of infection until it overtakes the migrating bacterial front and forces its collapse. Therefore, as infectivity or initial phage populations increase, the system transitions from a regime where bacterial abundances are regulated by chemotaxis and nutrient consumption to one where they are regulated by phage lysis. Near the transition between these two regimes the phage front becomes rough, exhibiting millimeter scale fluctuations in phage and bacterial densities.

## Materials and methods

### Experimental methods

All experiments were performed with lysogeny broth (LB) rich medium (10 gL−1 tryptone, 5 gL−1 yeast extract, 5 gL−1 NaCl). To create a swarm plate, LB medium was autoclaved with 0.3% w/v agar after autoclaving 5 mM MgSO4 and an appropriate CaCl2 concentration were added. Prior to cooling 100 mL of medium was measured in a sterile graduated cylinder and poured into a 15 cm diameter sterile plate. The plate was allowed to solidify at room temperature for 3 h. Plates were then transferred to a walk-in incubator 30 °C (Darwin Chambers) and allowed to reach thermal equilibrium for no <24 h prior to inoculation. All experiments reported here were performed at 30 °C.

To initiate an experiment, an overnight culture of Escherichia coli (E. coli) (MG1655, motile, Coli Genetic Stock Center #6300) was initiated in LB from frozen glycerol stocks. 10 μL of saturated overnight culture (≈1 × 106 cells) was taken from this culture and mixed with 10 μL phage P1 lysate and vortexed thoroughly before being inoculated into the center of the swarm plate. P1 lysates were titered by standard serial dilution and plating on top agar and counting plaques. Lysate titers were 1 × 1010 PFU/mL. Changing the initial phage population was accomplished by diluting the P1 lysate into LB medium prior to mixing with bacteria. Phage lysates were not used for more than a year and each new phage lysate that was made was titered by serial dilution and plating.

Plates were imaged using computer controlled Logitech webcams housed in light tight boxes with illumination provided by LED strips which encircled the plates and were turned on for 1 s per image acquisition [26]. Imaging occurred in one of two ways: either plates were left in light tight boxes and images were acquired once every 2–4 min (Fig. 1) or plates were housed in the incubator but were manually transferred to the imaging apparatus to acquire images at fixed points in time since inoculation (Fig. 2). All image analysis was performed with custom written Matlab scripts. For plates subjected to continuous imaging (every 2–4 min) the images were processed as described in a previous publication [26]. Briefly, a background image was constructed from the median projection of five images at the beginning of the acquisition before a colony formed. The center of the colony was determined using a circular Hough transform from an image acquired 24 h after inoculation. From this center, a radial line of pixels was extracted, and the image intensity recorded for each frame of the acquisition. The location of the bacterial front was determined by finding the outermost peak in the image intensity at all time points where the front could be detected. The bacterial front migration rate was then determined by linear regression (Fig. S3). The phage front location was determined by finding the point in this radial profile where the image intensity fell to 80% of its maximum (Fig. 1, yellow arrows).

For plates where intermittent images were acquired manually (e.g., 8, 14, and 19 h after inoculation, Fig. 2), background subtraction could not be performed using the median projection technique described above. Instead, we computed a radial profile of pixel intensities from the colony center at the earliest image acquired when the colony was small (8 h in the case of Fig. 2a). For a radial profile of pixel values, we computed a polynomial fit (fourth order) to the region of the image beyond the outermost bacterial front. We used this fit to construct a synthetic background image by extrapolating to the center of the plate and assuming azimuthal symmetry. The synthetic background image was then subtracted from the 19 h time point. The result is shown in Fig. 2. The bacterial and phage front locations were determined manually for the images in Fig. 2 using the same criteria described above.

To assess the reproducibility of the transition from the regime where nutrients regulate bacterial abundances to the regime where phage infections limit bacterial growth, we performed an additional set of at least five experiments at low (1 mM) and high (≥8 mM) CaCl2 concentrations and low and high initial phage densities. All of these experiments showed colony morphologies and dynamics consistent with the results shown in Fig. 2.

Plate reader experiments were performed in 48-well plates using a BMG Labtech Clariostar plate reader equipped with an incubator maintained at 30 °C. Media volumes in each well were 0.75 mL. The plate reader made automated optical density measurements on 5-min intervals with orbital shaking between measurements. Phage titer, adsorption rate, burst size, and bacterial carrying capacity were assayed using standard techniques, which are described in the Supplementary Appendix.

## Model

To interpret experimental observations, we developed a reaction-diffusion model to describe the spatio-temporal dynamics of bacterial and phage densities. The model is described graphically and mathematically in Box 1.

Our model includes susceptible bacteria B(x, t), resistant bacteria Br(x, t), infected bacteria I(x, t), phages P(x, t), nutrient n(x, t), and two chemoattractants c1(x, t) and c2(x, t). These populations are depicted graphically in Box 1a. The model is shown in Box 1b where a description of each term in the model is given. Model parameter values along with the source of values used in our simulations are given in Table 1.

Several assumptions are made in the model and justified below:

1. (1)

Bacterial growth and nutrient depletion: the depletion of the nutrient n leads to bacterial replication where the specific growth rate is assumed to follow Monod’s growth kinetics $$\frac{{{g}_{n}^{\left( {{\mathrm{max}}} \right)} \times {n}}}{{{K}_{n} \,+\, {n}}}.$$

2. (2)

Bacterial chemotaxis: the chemotaxis is assumed to be driven by gradients of two chemoattractants. The chemotactic velocity $${\vec{\it{v}}}\left( {{c}_1,{c}_2} \right) = {\upchi}_1 \times \nabla {\mathrm{log}}\left( {\frac{{1 \,+\, {c}_1{/a}_ - }}{{1 \,+\, {c}_1{/a}_ + }}} \right) + {\upchi}_2 \times \nabla {\mathrm{log}}\left( {\frac{{1 \,+\, {c}_2{/a}_ - }}{{1 \,+\, {c}_2{/a}_ + }}} \right)$$ models bacterial chemotaxis up the gradient of c1 and c2 with the log-adaptation range between a and a+ [30].

3. (3)

Resistant bacteria: the generation of a phage-resistant bacteria (Br) by spontaneous mutations is assumed to occur with probability pr = 10−5 per replication. Resistant bacteria (Br) are assumed to grow 20% slower than the susceptible bacteria B(sr = 0.2). We cannot measure these parameters directly and therefore they are constrained by a qualitative comparison to data and sensitivity is determined by simulations (Fig. S8).

4. (4)

Phage infection: the infection of bacteria by phage follows a simple mass action form η × B × P.

5. (5)

Latent period of infection: latency is modeled by introducing S = 10 auxiliary intermediate infection states of bacteria, I1, I2, …, Is taking place between the adsorption event and the production of phage progeny (Eq. (3), Box 1b). These intermediate states are a well-established mathematical method to model the dispersion of latency periods in the populations in deterministic models [31,32,33]. In Supplementary Appendix and Fig. S7, we show that multiple states of infection are necessary for our model to recapitulate the spatial patterns we observed in Fig. 1. It is important to note that our conclusions are not sensitive to S so long as it is ~≥10. These intermediate states do not have an explicit microscopic interpretation in terms of the phage infection process. Instead they permit us to capture the fact that the latency period is variable across the population of infected bacteria and avoid the computational complication of simulating time-delayed differential equations.

6. (6)

Bacterial growth-dependent phage physiology: to reproduce the experimental results, we included a reduction of phages’ burst size and extension of their latency time as nutrients are depleted and bacterial growth rates decline. As n declines, we assume that the burst size β(n) decreases and the latency time τ(n) increases as $$\beta ( {n} ) = \beta \times ( {{r}_b + (1 - {r}_b) \times \frac{{{g}_{n}({n})}}{{{g}_{n}({n} \,=\, {n}^0)}}} )$$ and $$\tau ( {n} ) = \tau /({r}_l + (1 - {r}_l) \times \frac{{{g}_{n}({n})}}{{{g}_{n}({n} \,=\, {n}^0)}})$$. Here $${g}_{n}\left( {n} \right) = \frac{{{g}_{n}^{\left( {{\mathrm{max}}} \right)} \times {n}}}{{{K}_{n} + {n}}}$$ is the specific growth rate and gn(n = n0) is the specific growth rate when nutrients are not depleted (n0 = 10 mN). We note that this dependence of phage infectivity on host physiology has been observed previously [34, 35]. We are able to constrain these parameters, but we cannot specify them quantitatively directly from our data (see Figs. S2, S4 and Supplementary Appendix). In Fig. S5, we compare our assumed dependence of burst size and latency period on growth rate with that observed in ref. [34] and find that they are similar. Other studies have shown similar dependences of burst size and latency period on growth rate (ref. [36] Fig. 2; ref. [37] Fig. 3).

### Sensitivity analysis

The sensitivity of several model assumptions was tested by comparing the fitted models with and without each assumption to well-mixed batch culture experiments, and the result is shown in Fig. S4. The spatial profiles of phage density are shown as a function S in Fig. S7. To further analyze the sensitivity of model parameters related to those assumptions, a Markov Chain Monte Carlo was performed. The posterior distributions for parameters generated by the adaptive Metropolis sensitivity analysis are shown in Fig. S8. Because the posterior distribution can give an approximation of the basin of attraction around a global minimum, the sensitivity of a parameter is reflected by the standard deviation of the posterior distribution (i.e., the smaller the standard deviation, the more sensitive to the variation of the parameter).

### Box 1 Description of the model

Panel A shows a graphical description of the modeling formalism developed to describe spatio-temporal phage–bacteria dynamics. Four populations are captured in the model and shown schematically: bacteria (B), infected bacteria (I), phage (P), and bacterial mutants that are resistant to phage infection (Br). These populations all depend explicitly on space and time and interact with three chemical fields: nutrients (n) and two chemoattractants (c1) and (c2). Sketches of the spatial profile of these chemical fields are shown in the plot below. Panel B shows the explicit equations used in our numerical simulations. The interpretation of each term is given.

## Results

To study phage–bacterial interactions in a spatially structured context, we used the rich medium (LB) low viscosity (0.3% w/v) agar plates. When E. coli is inoculated at the center of these plates, it rapidly consumes nutrients locally creating a gradient in the primary attractant (serine) and the secondary attractant (aspartate) that drives radially symmetric chemotactic migration of the population (rate 0.36 cm h−1, conditions here are identical to those studied in ref. [26] with the addition of phages). We inoculated an agar plate with a mixture of bacteria and phage (P1, virulent strain) at the center of the plate. Phage P1 requires calcium (CaCl2, ranging between 1 and 10 mM in our experiments) and magnesium (MgSO4, 5 mM) to infect E. coli [45]. The dependence of the infection on CaCl2 allows us to modulate the adsorption rate of phage by varying calcium concentration in the plate (MgSO4 concentration is fixed at 5 mM in all experiments shown here). We measured the difference in adsorption rate as a function of CaCl2 and found that it changed by a factor 2 between 1 and 10 mM CaCl2. We refer to the initial phage population as the number of plaque-forming units (PFU) in the inoculum.

Figure 1 shows the spatio-temporal dynamics of populations of bacteria (~1 × 106 cells/inoculum) and phages (~2.3 × 107 PFU/inoculum) for 1 mM CaCl2. At this relatively low calcium concentration, the phage adsorption rate is low. Figure 1a shows an image of the agar plate taken 9, 14, and 19 h after inoculation. The overall radial expansion of the bacterial population (referred to as bacterial front, the bright outer ring of the colony, orange arrow Fig. 1a) proceeds at a constant rate of 0.36 cm h−1. This rate of expansion is identical to bacteria migrating in the plates without phages present [26]. The bacterial front is followed by a deepening and widening black region in the center of the agar plate, whose outer boundary we refer to as the phage front (yellow arrow, Fig. 1a). This central black region is caused by a collapse of the local bacterial population due to phage predation. Radial profiles of the bacterial density were measured by extracting and averaging pixel intensities in background-subtracted images (see “Methods”). Figure 1b shows these radial density profiles of bacteria at the time points shown in Fig. 1a. Here the phage front is visible as a sharp decline in image intensity (bacterial density) near the center of the plate at later times. For example, the orange trace in Fig. 1b shows a radial profile at 19 h where the phage front is evident at a radius of ~3 cm, while that of the bacterial front is present at a radius of 6 cm. For the conditions shown in Fig. 1, the separation between the phage front and the bacterial front increases with time (compare red and orange traces, Fig. 1b). Thus, under these conditions, phages are not able to keep up with the expansion of the bacterial colony.

To confirm that the collapse in bacterial densities at the center of the plate was in fact driven by phage predation and to measure phage densities in the expanding bacterial front, we sampled a plate after 19 h of expansion at several distances from the center and measured the phage density (“Methods”). Figure 1c shows the phage population density (PFU) as a function of the radius where, as expected, we observe very high phage densities in regions where the image intensity is low. Unexpectedly, a small number of phages are present at the outer edge of the expanding bacterial colony.

How could the phage have reached the outer edge of the colony (radius 6 cm) in a period of 19 h? The diffusion constant of phage P1 in water is 4 × 10−8 cm2 s−1 [39] limiting diffusive transport on this timescale to ~0.1 cm. So, it appears passive transport of phage alone is insufficient to explain the presence of phage at distances of 6 cm from the site of inoculation. Previous studies of plaque formation have found that phage plaques expand through lawns of dense bacteria as a traveling wave with speeds up to 0.025 cm h−1 [12, 13]. At this rate of expansion, we expect the phage population to travel <0.5 cm over the 19 h duration of the experiment. These quantitative considerations strongly suggest that the phage could not have reached the outer edge of the expanding colony by passive transport alone.

Instead, we suggest that the phage travels along with migrating bacteria either by attaching to the surface of swimming bacterial cells and not injecting DNA or by being transported during the latent period of infection. If phage is hitchhiking with the moving bacterial front, we expect plaques to form behind the front as the hitchhiking phage completes multiple rounds of infection on the host. We observe the formation of these plaques in conditions where the bacterial front is moving quickly relative to the phage front (Fig. 2a, lower-left corner, Fig. 3a, b). Note that in these images the visible plaques are well behind the outermost bacterial front. Visible plaques typically harbor 107–108 phage per plaque [14] and therefore require many (>10) rounds of lysis and infection. Given the latency period of at least 1 h for phage P1, we expect visible plaques take on the order of 10 h to form. In this time the bacterial front travels ~3.5 cm and as a result, the visible plaques arising from hitchhiking phages are present well behind the primary bacterial front.

In the conditions shown in Fig. 1, the phage front is moving at a slower rate than the bacterial front. As a result, we expect that phages are being diluted out of the expanding bacterial front and therefore were the front to expand indefinitely the bacterial population would be free from phage infection. So, while phage must be actively transported by the migrating bacterial front, in the conditions shown in Fig. 1, they are unable to keep up with the traveling bacterial wave.

To describe the spatio-temporal dynamics observed in Fig. 1a–c, we developed a deterministic ordinary differential equation model of the phage–bacteria system, which describes the dynamics of bacterial and phage populations in space and time. Numerical simulations of the model are shown in Fig. 1d–f where we find that the model captures the core features of the data. A schematic of the model is shown in Box 1a and a detailed description in “Methods”, Box 1b, and Supplementary Appendix.

Are bacteria always capable of moving faster than their phage predators, or can phage populations slow down or even stop the advancing bacterial front? To investigate this question, we repeated our experiment for a broad range of parameters characterizing phage infectivity and initial population size. Figure 2a shows snapshots of bacterial populations taken 19 h after inoculation as a function of CaCl2 concentration on agar plates (x-axis) and the initial number of phages in the inoculum (y-axis). Higher concentrations of CaCl2 increase the adsorption rate of phages [45], thereby making it easier for them to spread. This is indeed seen as a systematic increase in the radius of the inner black region (phage front), as one moves from left to right in Fig. 2a, bottom row. Similarly, increasing the initial phage density speeds up the phage front even at fixed CaCl2 concentration (Fig. 2a, left column). Increasing both CaCl2 concentration and initial phage population size above a certain threshold results in a slowed bacterial front (upper-right corner, Fig. 2a). Figure 2a suggests that at low infectivity and initial phage populations the bacterial front is able to move faster than the phage front (lower-left region), whereas at high infectivity or starting phage populations bacteria are overtaken and likely evolve resistance in order to form a migrating front (upper-right region).

To test these conclusions, we made two additional measurements. First, for plates above and below the transition (1 or 8 mM CaCl2 and 1.55 × 105 phages), we tested bacterial populations for phage resistance after the front expansion process had proceeded for 19 h. Indeed, at low infectivity (1 mM CaCl2) the outermost bacterial front is comprised of susceptible bacteria. In contrast, at high infectivity, when a smaller bacterial colony is formed, the entire bacterial population is phage resistant (Fig. S1, Supplementary Appendix). Second, we made time-lapse measurements of a series of plates with varying initial phage population sizes ranging from 1.55 × 104 to 1.55 × 108 and measured the speed of the phage and bacterial fronts (see Movies S1–S4). We found that the bacterial front migration rate did not vary substantially with initial phage population, but that the phage front speed increased more than threefold with a 1000-fold increase in the starting phage population size (Fig. S3, Supplementary Appendix).

Based on these measurements, we conclude that at low initial phage populations and low infectivity the bacterial front manages to escape phage predation. In contrast, at high initial phage populations, or infectivity, the bacterial population fails to begin migration and instead must evolve phage resistance before expanding across the plate. As a result, when the phage population inhibits the bacterial expansion, this inhibition is temporary due to the growth of phage-resistant bacterial strains [46]. For phage P1, these mutant bacteria arise at a rate of about 10−5 per generation [44]. Notice that just above this transition (e.g., 8 mM CaCl2, 1 × 104 phages or 1 mM CaCl2, 1 × 108 phages; Fig. 2a) the bacterial colony exhibits sectors which potentially arise from clonal expansion started from single resistant mutants. These dynamics are reminiscent of spatial antibiotic resistance patterns [47]. Supplementary Movie S1 shows an expanding bacterial front at 10 mM CaCl2 and 1.5 × 105 initial phage population size where we see an expanding front of bacteria which is halted after 12 h of expansion only to resume expanding, presumably with resistant bacteria. However, when the phage load is large, and infectivity high, all susceptible bacteria are eliminated at the outset, resulting in a delayed but spatially symmetric expansion of the resistant bacterial population (Fig. 2a, upper-right corner).

To quantify the speed of both phage and bacterial fronts, we measured their respective locations in space under different experimental conditions. Figure 2b, c shows the position of the outer (bacterial) front and the width of the bright region between bacterial and phage fronts measured 19 h after inoculation. These measurements show the properties of the system on both sides of the transition: the bright area in the lower-left corner of the panel Fig. 2b shows that for low phage loads bacterial chemotaxis proceeds at a rate that is approximately independent of the phage load and CaCl2 concentration. Above the transition, bacterial populations are decimated at the outset of the experiment and the remaining resistant bacteria migrate only a short distance by 19 h. The progressive darkening of Fig. 2b in the upper-right corner quantifies the slowing of the migrating bacterial front by phages under increasing initial phage population sizes and infectivity. Finally, Fig. 2c quantifies the width of the ring where bacteria are abundant (the distance between the bacterial and phage fronts). This distance shrinks to zero as phages overtake bacteria (black region, upper-right corner, Fig. 2c).

Overall Fig. 2a–c shows the existence of two distinct parameter regimes in which bacterial densities are either regulated by migration and access to nutrients or phage lysis. As either the phage load (initial population) or phage adsorption rate (CaCl2 concentration) increases, the speed of the phage front increases, and eventually causes a transition from the regime where bacterial abundances are set by chemotaxis and nutrient availability to one where phage lysis limits total bacterial abundances.

Figure 2d–f shows that our deterministic ODE model reproduces the general properties of the measured phase diagram shown in Fig. 2a–c. The intensity profiles shown in Fig. 2d include the resistant bacteria, which dominate the bacterial populations in the upper-right corner of the diagram but are not significant at or below the transition along the diagonal. As we observe experimentally, the model predicts that increasing the adsorption rate will lead to a transition from a regime where phages are progressively lost from the bacterial front to one where phages overtake the bacterial front resulting in collapse. Figure 2 is the central finding of this study.

To better understand the nature of the transition between the two regimes characterized by low infectivity and low initial phage population or high infectivity and high initial phage density, we studied a simple model of phage reproduction in a bacterial traveling wave (Fig. S6, Supplementary Appendix). In this model, as bacteria are migrating, phages are lost if they do not infect the host. The ability of phages to be retained in the migrating front is therefore controlled by a balance between phage infection and bacterial migration. Using this formalism, we analytically compute a threshold adsorption rate (ηc) which defines the transition between phage populations either growing, and thereby driving bacterial colony collapse, or being lost from the migrating front. We find ηc 2 × 10−8 mL/h which agrees well with the adsorption rate at which we observe the transition experimentally and computationally (Fig. 2).

For conditions close to the transition region, where the phage front speed is only slightly slower than that of the bacterial front (e.g., 4 mM CaCl2, 1 × 104 phage, Fig. 2a), the phage front becomes rough, exhibiting a star-like spatial structure with centimeter-long phage-dominated dark regions extending into lighter regions with high bacterial densities. The roughening of the phage front near the transition suggests that there are large differences in bacterial densities for regions of the phage front over length scales of a millimeter or more. In plates where no phages are added the profile of bacterial densities is smooth (Fig. 1b in [19]), ruling out nutrient inhomogeneities. The strong spatial variability in bacterial densities suggests a role for contingencies in infection histories in spatially structuring the phage–bacteria interactions.

To document the roughening of the phage front more carefully, we studied a single plate in detail. Figure 3 shows two snapshots (19 and 24 h after initiation) of a plate containing 5 mM CaCl2 and 4.7 × 104 phage in the inoculum. These images reveal a clear spatial structure in the phage front characterized by alternating black and white regions that are more spatially extended than those shown in Fig. 1a. In this condition, the dark regions (where bacteria are being killed by phage) expand rapidly, at a rate approaching the speed of the bacterial front (compare the width of the light area near protruding black regions at 19 and 24 h in Fig. 3a, b). In contrast, in Fig. 1a well below the transition the black region expands at a steady, but slower, rate than the bacterial front and the rate of expansion is approximately independent of the azimuthal direction.

To better quantify the spatial structure of the dark regions visible in Fig. 3a, b, we computed statistics of image intensity for background-subtracted images in annuli of pixels falling within a fixed range of radii. Figure 3c shows the azimuthally averaged image intensity as a function of the radius at several times after the plate was initiated. Figure 3d shows the standard deviation of all pixel intensities at a fixed radius. Figure 3d clearly shows that the variation in pixel intensities is maximal at intermediate radii (peak around 4 cm for 24 h purple trace). The peak in pixel intensity variability marks the center of the phage front which is comprised of regions where phage (dark) and bacteria (light) dominate. This peak in the variability of pixel intensities migrates ~2 cm between 19 and 24 h. The outermost bacterial front migrates approximately the same distance over this time interval. Therefore, as we expect, the roughened phage front moves at a pace that is similar to that of the outermost bacterial front in conditions near the transition from a regime where bacterial abundances are nutrient regulated to one where they are phage regulated.

To further elaborate on this observation, in Fig. 3e we plotted the normalized histogram of bacterial abundances (quantified by image intensity, y-axis) at 24 h as a function of the distance from the center (x-axis). These histograms were computed for a set of radii from the center of the plate. In Fig. 3e, for distance around 4 cm, one can see that the distribution of bacterial abundances is, in fact, bimodal, corresponding to white and black regions visible in Fig 3a, b and the position of the largest variation in Fig. 3d. The distribution of pixel intensities at a radius of 4 cm is shown in Fig. 3f. Simulations show that this spatial structure could arise from spatially inhomogeneous initial phage densities (Fig. S9).

Therefore, for 5 mM CaCl2 and 4.7 × 104 phage (PFU) in the inoculum, phages keep up with bacterial front expansion in some directions but are left behind in others. This suggests that the local dynamics in our system are potentially driven by positive feedback which amplifies initially small variations into macroscopic differences manifesting themselves at a scale of several centimeters.

## Discussion

We have shown how spatial structure in bacterial populations driven by chemotaxis interacts with phage population size and adsorption rate to determine the outcome of bacteria–phage interactions. Our study has three important results.

First, we find that nonmotile phages are able to hitchhike with expanding bacterial populations by repeatedly re-infecting cells in an expanding bacterial front (Fig. 1). This observation suggests that the latent period of phage infection, or another mechanism by which phages attach to swimming bacteria, permit phage to hitchhike with their hosts into new spatial niches. At present, we cannot definitively determine which mechanism of hitchhiking is dominant. However, the latency time is on the order of 1 h [48, 49]. On this timescale, the bacterial front travels 0.36 cm suggesting that phages transport during the latent period would outpace passive transport. In contrast, the time for DNA injection during infection is typically 1–10 min [50, 51], but to our knowledge has not been precisely measured in phage P1. We cannot rule out the possibility that phages are transported while being attached to the cell prior to DNA injection. The fact that hitchhiking occurs suggests that the timescale over which phages attach to, infect, and subsequently lyse bacterial cells can be related to the spatial structure of phage–bacteria populations. To our knowledge, the relationship between the physiology of phage infecting bacteria and the spatial transport of phage by migrating bacteria has not previously been appreciated.

Second, Fig. 2 shows how the outcome of phage–bacteria interactions depends on population size and infectivity. A transition region defines a boundary between regimes, one where phage-susceptible bacteria escape phage infection, and another where the bacteria are forced to evolve phage resistance to survive. This observation has important implications for understanding phage–bacteria interactions in complex environmental contexts such as lakes or the particle-filled water columns in the ocean, where bacterial growth is variable due to transient chemotaxis driven exploitation of patchy resources [27]. In particular, for phages to dominate a migrating and growing bacterial population requires high initial population densities or high adsorption rates. In situations where these conditions are not met, phages remain able to attack smaller localized bacterial populations, which could limit their overall fecundity and possibly their impact on bacterial genome evolution via transduction [52].

It is interesting to note that we observe the phage-regulated regime when infectivity (adsorption rates) is high and the nutrient-regulated regime when infectivity is low (Fig. 2). Therefore, for phage infecting motile host populations, higher infectivity is likely favored. This result stands in contrast to results obtained with expanding phage plaques in bacterial lawns [14] where selection for large plaques favors lower infectivity [15]. It would appear then that the evolution of phage life-history traits may depend qualitatively on the motility of the bacterial host.

Our modeling framework confirmed that a key feature responsible for the spatial structure in phage–bacteria populations is the strong dependence of phage infection on host physiology [19, 34, 36, 37, 53,54,55]. The decreasing burst size and increasing latency of phage infections with host growth rate interact with the self-organizing nutrient gradients in migrating bacterial populations to give rise to regions of space where phage is excluded. Previous studies suggest this dependence on host physiology arises from limits on the rate of synthesis of new phages and on the size of host cells prior to lysis [34]. If this mechanism is indeed responsible, it suggests that the dependence of phage infectivity on host physiology may be generic. In this case, there is a clear advantage for slow growing bacterial populations in spatial niches with substantial phage predation pressure.

Despite the overall success of the model in describing the dynamics in our phage–bacteria system, we do note that the model fails to capture certain features of the data. In particular, at 8 mM CaCl2 and 104 or 105 phage we observe large, dense, colonies forming (Fig. 2a), whereas the model predicts a dim outer ring and central region of resistant bacteria. We suspect that the reason for this disagreement is the presence of additional chemoattractants in the rich media that are not modeled explicitly, potentially threonine [25], which permit the chemotaxis of resistant bacteria even if the susceptible population (the outer ring) has already consumed serine and aspartate. The presence of such an attractant would give rise to larger colonies since resistant bacteria which arise at the center of the colony could then migrate outward via chemotaxis. We omitted this feature in our model for the sake of simplicity.

Third, there is a role of contingency in determining the spatial structure of the phage front for communities near the transition (Fig. 3a, b), where centimeter-wide spatially extended regions are alternately dominated by phage and bacteria. A full accounting of this phenomenon awaits future work; however, it appears that large differences in bacterial populations are amplified from relatively small fluctuations in the inoculum with a large number of phages (between 104 and 108 in our experiments). At first glance, the alternating black and white regions in the phage front are reminiscent of sectors in microbial range expansion with two fluorescently labeled strains with the same fitness [56]. In our system, the roughening may then result from phage and bacteria having nearly equal rates of expansion near the transition and the fact that phages can be present in the bacterial front at very low concentrations (Fig. 1). Indeed, our results suggest that the roughened phage front near the transition does not arise from phage-resistant bacterial populations. First, the regions of the front which are dominated by bacteria (Fig. 3a, b) are eventually overtaken by dark, phage-dominated regions. Second, a sample taken from the phage front showed bacteria at this spatial location to be phage susceptible (Fig. S1). Our results suggest that resistant bacteria typically arise at a later time and have very different fan-like spatial structure.

To better understand these spatial fluctuations will require a detailed understanding of spatially localized phage fluctuations within the inoculum before and just after the start of migration. Furthermore, exploring any mechanisms of positive feedback present during multiple rounds of infection that might be present and may amplify small fluctuations in phage and bacterial populations. One possible mechanism for the positive feedback is that phage which initially succeeds in killing the bacteria limit nutrient consumption which subsequently drives the growth of bacteria which can then be infected by phage. Weitz et al. [57] used the Lotka–Volterra framework to demonstrate that reduced adsorption rate as bacteria approach stationary state can provide sufficient feedback to give rise to bi-stability, potentially driving the roughening of the phage front we observe.

We have shown that actively moving hosts impose an important set of selection pressures on phages. For example, we expect that phages with infection dynamics inhibiting chemotaxis or with very short latency periods may be at a disadvantage with respect to colonizing new spatial niches. Chemotaxing bacteria thereby add an additional selection pressure on phages with extremely aggressive infection cycles.

## References

1. Datta MS, Sliwerska E, Gore J, Polz MF, Cordero OX. Microbial interactions lead to rapid micro-scale successions on model marine particles. Nat Commun. 2016;7:11965.

2. Michalak AM, Anderson EJ, Beletsky D, Boland S, Bosch NS, Bridgeman TB, et al. Record-setting algal bloom in Lake Erie caused by agricultural and meteorological trends consistent with expected future conditions. Proc Natl Acad Sci USA. 2013;110:6448–52.

3. Campbell A. Conditions for the existence of bacteriophage. Evolution. 1961;15:153.

4. Levin BR, Stewart FM, Chao L. Resource-limited growth, competition, and predation—a model and experimental studies with bacteria and bacteriophage. Am Nat. 1977;111:3–24.

5. Thingstad TF. Elements of a theory for the mechanisms controlling abundance, diversity, and biogeochemical role of lytic bacterial viruses in aquatic systems. Limnol Oceanogr. 2000;45:1320–8.

6. Bohannan BJ, Lenski RE. Effect of resource enrichment on a chemostat community of bacteria and bacteriophage. Ecology. 1997;78:2303–15.

7. Wang Z, Goldenfeld N. Fixed points and limit cycles in the population dynamics of lysogenic viruses and their hosts. Phys Rev E. 2010;82:171–18.

8. Jover LF, Cortez MH, Weitz JS. Mechanisms of multi-strain coexistence in host–phage systems with nested infection networks. J Theor Biol. 2013;332:65–77.

9. Chao L, Levin BR, Stewart FM. A complex community in a simple habitat: an experimental study with bacteria and phage. Ecology. 1977;58:369–78.

10. Mizoguchi K, Morita M, Fischer CR, Yoichi M, Tanji Y, Unno H. Coevolution of bacteriophage PP01 and Escherichia coli O157:H7 in continuous culture. Appl Environ Microbiol. 2003;69:170–6.

11. Waterbury JB, Valois FW. Resistance to co-occurring phages enables marine synechococcus communities to coexist with cyanophages abundant in seawater. Appl Environ Microbiol. 1993;59:3393–9.

12. Fort J, Méndez V. Time-delayed spread of viruses in growing plaques. Phys Rev Lett. 2002;89:786–4.

13. Yin J, McCaskill JS. Replication of viruses in a growing plaque—a reaction-diffusion model. Biophys J. 1992;61:1540–9.

14. Gallet R, Shao Y, Wang I-N. High adsorption rate is detrimental to bacteriophage fitness in a biofilm-like environment. BMC Evolut Biol. 2009;9:241–12.

15. Roychoudhury P, Shrestha N, Wiss VR, Krone SM. Fitness benefits of low infectivity in a spatially structured population of bacteriophages. Proc Biol Sci. 2014;281:20132563–9.

16. Dennehy JJ, Abedon ST, Turner PE. Host density impacts relative fitness of bacteriophage Phi6 genotypes in structured habitats. Evolution. 2007;61:2516–27.

17. Eriksen RS, Svenningsen SL, Sneppen K, Mitarai N. A growing microcolony can survive and support persistent propagation of virulent phages. Proc Nat Acad Sci. 2018;115:337–42.

18. Sutherland IW, Hughes KA, Skillman LC, Tait K. The interaction of phage and biofilms. FEMS Microbiol Lett. 2004;232:1–6.

19. Vidakovic L, Singh PK, Hartmann R, Nadell CD, Drescher K. Dynamic biofilm architecture confers individual and collective mechanisms of viral protection. Nat Microbiol. 2018;3:26–31.

20. Hughes KA, Sutherland IW, Jones MV. Biofilm susceptibility to bacteriophage attack: the role of phage-borne polysaccharide depolymerase. Microbiology. 1998;144:3039–47.

21. Corbin BD, McLean RJ, Aron GM. Bacteriophage T4 multiplication in a glucose-limited Escherichia colibiofilm. Can J Microbiol. 2001;47:680–4.

22. Abedon ST, editor. Bacteriophage ecology: population growth, evolution, and impact of bacterial viruses. 2008. Cambridge University Press; 2008 May 1.

23. Heilmann S, Sneppen K, Krishna S. Sustainability of virulence in a phage-bacterial ecosystem. J Virol. 2010;84:3016–22.

24. Heilmann S, Sneppen K, Krishna S. Coexistence of phage and bacteria on the boundary of self-organized refuges. Proc Nat Acad Sci. 2012;109:12828–33.

25. Adler J. Chemotaxis in bacteria. Science. 1966;153:708–16.

26. Fraebel DT, Mickalide H, Schnitkey D, Merritt J, Kuhlman TE, Kuehn S. Environment determines evolutionary trajectory in a constrained phenotypic space. Elife. 2017;6:e24669.

27. Stocker R, Seymour JR. Ecology and physics of bacterial chemotaxis in the ocean. Microbiol Mol Biol Rev. 2012;76:792–812.

28. Allweiss B, Dostal J, Carey KE, Edwards TF, Freter R. The role of chemotaxis in the ecology of bacterial pathogens of mucosal surfaces. Nature. 1977;266:448–50.

29. Chet I, Mitchell R. Ecological aspects of microbial chemotactic behavior. Annu Rev Microbiol. 1976;30:221–39.

30. Cremer J, Honda T, Tang Y, Wong-Ng J, Vergassola M, Hwa T. Chemotaxis as a navigation strategy to boost range expansion. Nature. 2019;575:658–63. https://doi.org/10.1038/s41586-019-1733-y.

31. Getz WM, Dougherty ER. Discrete stochastic analogs of Erlang epidemic models. J Biol Dyn. 2018;12:16–38.

32. Hurtado PJ, Kirosingh AS. Generalizations of the ‘Linear Chain Trick’: incorporating more flexible dwell time distributions into mean field ODE models. J Math Biol. 2019;79:1831–83.

33. Champredon D, Dushoff J, Earn DJD. Equivalence of the Erlang-distributed SEIR epidemic model and the renewal equation. SIAM J Appl Math 2018;78:3258–78.

34. Hadas H, Einav M, Fishov I, Zaritsky A. Bacteriophage T4 development depends on the physiology of its host Escherichia coli. Microbiology. 1997;143:179–85.

35. Middelboe M. Bacterial growth rate and marine virus-host dynamics. Microb Ecol. 2000;40:114–24.

36. Golec P, Karczewska-Golec J, Łoś M, Węgrzyn G. Bacteriophage T4 can produce progeny virions in extremely slowly growing Escherichia colihost: comparison of a mathematical model with the experimental data. FEMS Microbiol Lett. 2014;351:156–61.

37. Choua M, Bonachela JA. Ecological and evolutionary consequences of viral plasticity. Am Naturalist. 2019;193:346–58.

38. Fehér T, Karcagi I, Blattner FR, Pósfai G. Bacteriophage recombineering in the lytic state using the lambda red recombinases. Microb Biotechnol. 2011;5:466–76.

39. Baltus RE, Badireddy AR, Delavari A, Chellam S. Free diffusivity of icosahedral and tailed bacteriophages: experiments, modeling, and implications for virus behavior in media filtration and flocculation. Environ Sci Technol. 2017;51:1433–40.

40. Fu X, Kato S, Long J, Mattingly HH, He C, Vural, et al. Spatial self-organization resolves conflicts between individuality and collective migration. Nat Commun. 2018;9:1–12. https://doi.org/10.1038/s41467-018-04539-4.

41. Yang Y, Pollard AM, Höfler C, Poschet G, Wirtz M, Hell R, et al. Relation between chemotaxis and consumption of amino acids in bacteria. Mol Microbiol. 2015;96:1272–82. https://doi.org/10.1111/mmi.13006.

42. Hama H, Shimamoto T, Tsuda M, Tsuchiya T. Characterization of a novel L-serine transport system in Escherichia coli. J Bacteriol. 1988;170:2236–9.

43. Schellenberg GD, Furlong CE. Resolution of the multiplicity of the glutamate and aspartate transport systems of Escherichia coli. J Biol Chem. 1977;252:9055–64.

44. Franklin NC. Mutation in gal U gene of E. coli blocks phage P1 infection. Virology. 1969;38:189–91.

45. Thomason LC, Costantino N, Court DL. E. coli genome manipulation by P1 transduction. Curr Protoc Mol Biol. 2007;Chapter 1:Unit 1.17.

46. Demerec M, Fano U. Bacteriophage-resistant mutants in Escherichia Coli. Genetics. 1945;30:119–36.

47. Baym M, Lieberman TD, Kelsic ED, Chait R, Gross R, Yelin I, Kishony R. Spatiotemporal microbial evolution on antibiotic landscapes. Science. 2016;353:1147–51.

48. De Paepe M, Taddei F. Viruses’ life history: towards a mechanistic basis of a trade-off between survival and reproduction among phages. PLoS Biol. 2006;4:e193–9.

49. Wall JD, Harriman PD. Phage P1 mutants with altered transducing abilities for Escherichia coli. Virology. 1974;59:532–44.

50. García LR, Molineux IJ. Rate of translocation of bacteriophage T7 DNA across the membranes of Escherichia coli. J Bacteriol. 1995;177:4066–76.

51. Novick SL, Baldeschwieler JD. Fluorescence measurement of the kinetics of DNA injection by bacteriophage lambda into liposomes. Biochemistry. 1988;27:7919–24.

52. Dixit PD, Pang TY, Studier FW, Maslov S. Recombinant transfer in the basic genome of Escherichia coli. Proc Nat Acad Sci. 2015;112:9070–5.

53. Rabinovitch A, Fishov I, Hadas H, Einav M, Zaritsky A. Bacteriophage T4 development in Escherichia coli is growth rate dependent. J Theor Biol. 2002;216:1–4.

54. Edwards KF, Steward GF. Host traits drive viral life histories across phytoplankton viruses. Am Nat. 2018;191:566–81.

55. Birch EW, Ruggero NA, Covert MW. Determining host metabolic limitations on viral replication via integrated modeling and experimental perturbation. PLoS Comput Biol. 2012;8:e1002746–12.

56. Hallatschek O, Hersen P, Ramanathan S, Nelson DR. Genetic drift at expanding frontiers promotes gene segregation. Proc Natl Acad Sci USA. 2007;104:19926–30.

57. Weitz JS, Dushoff J. Alternative stable states in host–phage dynamics. Theor Ecol. 2007;1:13–9.

## Acknowledgements

This research has received funding from the European Research Council under the European Union’s Seventh Framework Programme (FP/2007 2013)/ERC Grant Agreement No. 740704. DP and SK acknowledge the support from the National Science Foundation Physics Frontiers Center Program (PHY 0822613 and PHY 1430124). This work was performed in part at the Aspen Center for Physics, which is supported by National Science Foundation grant PHY 1607611.

## Author information

Authors

### Corresponding authors

Correspondence to Sergei Maslov, Kim Sneppen or Seppe Kuehn.

## Ethics declarations

### Conflict of interest

The authors declare that they have no conflict of interest.

Publisher’s note Springer Nature remains neutral with regard to jurisdictional claims in published maps and institutional affiliations.

## Rights and permissions

Reprints and Permissions

Ping, D., Wang, T., Fraebel, D.T. et al. Hitchhiking, collapse, and contingency in phage infections of migrating bacterial populations. ISME J 14, 2007–2018 (2020). https://doi.org/10.1038/s41396-020-0664-9

• Revised:

• Accepted:

• Published:

• Issue Date:

• DOI: https://doi.org/10.1038/s41396-020-0664-9

• ### Spatial regulation of cell motility and its fitness effect in a surface-attached bacterial community

• Emrah Şimşek
• Emma Dawson
• Minsu Kim

The ISME Journal (2022)

• ### Phage co-transport with hyphal-riding bacteria fuels bacterial invasion in a water-unsaturated microbial model system

• Xin You
• René Kallies
• Lukas Y. Wick

The ISME Journal (2022)


text:
Using operators" /> 2. Operators - PyOperators

# 2. Operators

## 2.1. Using operators

The Operator class and its subclasses are function factories. It means that in order to perform computations using an operator class, we first need to create an instance of it:

A = FFTOperator(1024)

and then use the instance as a function. The object A is a Python callable and takes numpy ’s N-dimensional array object as inputs and outputs:

>>> pyoperators.memory.verbose = True
>>> x = np.arange(1024, dtype=complex)
>>> y = A(x)
Info: Allocating (1024,) complex128 = 0.015625 MiB in FFTOperator.

When using the operator in such a way, a no-side-effect policy is enforced: it is garanteed that the input array will not be modified and as a consequence, a new buffer will be allocated every time the operator is called.

Similarly to ufuncs, such behaviour can be changed by providing the output array:

>>> pyoperators.memory.verbose = True
>>> y = np.empty(1024, dtype=complex)
>>> A(x, out=y)    # or simply A(x, y)

In-place operations can be performed in a similar way by providing the input array as the output.

In this documentation, the same term operator will be used for the Operator class, subclasses and instances, though the context will disambiguate the meaning.

## 2.2. Manipulating operators

Operators are easy to manipulate: they can be multiplied by a scalar, combined by addition, element-wise multiplication, composition or partition. The synthax uses the usual arithmetic signs, but be careful that the * sign depends on the operands’ linear flag: if both operands are linear, it stands for composition otherwise it stands for element-wise multiplication.

>>> A = DiagonalOperator([1., 2.])
>>> B = DiagonalOperator([1., 1.])
>>> A.flags.linear, B.flags.linear
(True, True)
>>> x = [2, 2]
>>> np.allclose((3 * A)(x), 3 * A(x))
True
>>> np.allclose((A + B)(x), A(x) + B(x))
True
>>> np.allclose(A(B)(x), A(B(x)))
True
>>> np.allclose((A * B)(x), A(B(x)))  # because A and B are linear
True
>>> np.allclose(MultiplicationOperator([A, B])(x), A(x) * B(x))
True

Unless an algebraic simplification is possible, the resulting operator is a composite operator:

 addition AdditionOperator $$A(x) + B(x)$$ element-wise multiplication MultiplicationOperator $$A(x) \times B(x)$$ composition CompositionOperator $$A(B(x))$$ partition BlockColumnOperator $$\begin{bmatrix} A \\ B \end{bmatrix}$$ BlockDiagonalOperator $$\begin{bmatrix} A & 0 \\ 0 & B \end{bmatrix}$$ BlockRowOperator $$\begin{bmatrix} A & B \end{bmatrix}$$

The conjugate, transpose, adjoint and inverse operators, when defined, can be obtained by using the following attributes:

 conjugate .C transpose .T adjoint .H inverse .I

For example:

>>> o = Operator()
>>> o.T.C is o.H
True
>>> o = Operator(flags='real,symmetric')
>>> o.T is o.H is o
True

## 2.3. Creating a new operator

Operators can be created in two ways. The first one is to define a direct function which will replace the usual matrix-vector operation and to instantiate the Operator class by passing the function as the first argument:

>>> def f(x, out):
...     out[...] = 2 * x
>>> P = Operator(f)

Transforming a single-argument ufunc into an Operator instance is straightforward:

>>> sqrt = Operator(np.sqrt)

The alternative way is more flexible, it consists in subclassing the Operator class:

>>> class MyOperator(Operator):
...     def __init__(self, coef):
...         self.coef = coef
...         Operator.__init__(self)
...     def direct(self, x, out):
...         out[...] = self.coef * x
...
>>> P = MyOperator(2)

## 2.4. Operator’s data type

The operator’s data type is a data type object (an instance of numpy.dtype class). It can be set using the dtype keyword.

>>> a = Operator(dtype=np.float32)
>>> a.dtype
dtype('float32')

It is used to determine the output data type, as being the common type of the operator and input data types, following the standard coercion rules. For example:

>>> a = DiagonalOperator([1, 2])
>>> a.dtype
dtype('int64')
>>> a([1, 1j]).dtype
dtype('complex128')
>>> a(np.array([2, 2], np.uint8)).dtype
dtype('int64')

The operator’s data type can be equal to None (the default), in which case the output data type is always the input data type.

## 2.5. Operator’s flags

An operator P can have the following algebraic properties, accessible with the flags attribute:

 linear real conj P = P symmetric P T = P hermitian P H = P idempotent P P = P involutary P P = I orthogonal P T P = I unitary P H P = I

They can be set using the flags keyword:

>>> def f(x, out):
...     out[...] = -x
>>> P = Operator(direct=f, flags='symmetric,involutary')

or by using operator decorators:

>>> @pyoperators.flags.symmetric
... @pyoperators.flags.involutary
... class MyOperator(Operator):
...     def direct(self, x, out):
...         out[...] = -x
...
>>> P = MyOperator()

These flags are used to simplify expressions:

>>> C = Operator(flags='idempotent')
>>> C * C is C
True
>>> D = Operator(flags='involutary')
>>> D * D
IdentityOperator()

Other properties are described by the flags attribute:

 square input and output have the same shape separable can be separated if applied by or applying on a block operator inplace handle inplace operations (more info) update_output can update the operator output (more info) alignment_input only handle aligned input alignment_output only handle aligned output contiguous_input only handle contiguous input contiguous_output only handle contiguous output shape_input explicit, implicit or unconstrained (more info) shape_output explicit, implicit or unconstrained (more info)

## 2.6. Operator’s input and output shapes

The Operator class has a flexible way to deal with inputs and outputs. Its output shape can be:

explicit: the operator only returns arrays of a specified shape.

implicit: the output shape is derived from the input shape through the method reshapein.

unconstrained: the output shape does not depend on the input shape.

Likewise, its input shape can be:

explicit: the operator only applies over arrays of a specified shape.

implicit: the operator can only apply over arrays whose shape is derived from the output shape through the method reshapeout.

unconstrained: any input shape can be handled by the operator.

The operator’s flags record this information in the shape_input and shape_output attributes. If the output (input) shape is

• explicit: the operator’s attribute shapeout(in) is equal to that tuple. The reshapein(out) method should not be overridden.
• implicit: the attribute shapeout(in) is None and the method reshapein(out) applied over the input (output) shape must return the output (input) shape.
• unconstrained: the attribute shapeout(in) is None. The reshapein(out) should not be overridden.

### Operator with explicit input and output shape.

The explicit shapes are specified using the shapein and shapeout keywords. The following example appends a zero to a fixed-size input.

>>> class Op(Operator):
...     def __init__(self, value):
...         Operator.__init__(self, shapein=3, shapeout=4)
...         self.value = value
...     def direct(self, input, output):
...         output[0:3] = input
...         output[3] = self.value
...
>>> op = Op(0.)
>>> op.shapein, op.shapeout
((3,), (4,))
>>> op([3., 2. ,1.])
array([3., 2., 1., 0.])

### Operator with implicit input shape and explicit output shape.

This case does not happen because the input shape can be obtained from the explicit output shape and the reshapeout method.

### Operator with unconstrained input shape and explicit output shape.

Such operator is obtained by only setting the shapeout keyword. The following example returns an array of size 2 whose elements are the sum and product of the input elements.

>>> class Op(Operator):
...     def __init__(self):
...         Operator.__init__(self, shapeout=2)
...     def direct(self, input, output):
...         output[0] = np.sum(input)
...         output[1] = np.product(input)
...
>>> op = Op()
>>> op.shapein, op.shapeout
(None, (2,))
>>> op([1., 2., 3., 4.])
array([ 10., 24.])

### Operator with explicit input shape and implicit output shape

This case does not happen because the output shape can be obtained from the explicit input shape and the reshapein method.

### Operator with implicit input and output shape

This operator defines both reshapein and reshapeout methods. Square-decorated operators are examples of this kind of operators: their reshapein and reshapeout methods simply are lambda x:x by default. The interest for an implicit output shape operator of also handling implicit input shapes arises when a reverse operator such as .T or .H is defined because in which the reshapein and reshapeout methods are swapped. The operator in the following example adds a zero to its input.

>>> @pyoperators.flags.linear
... class Op(Operator):
...     def direct(self, input, output):
...         output[:-1] = input
...         output[-1] = 0
...     def transpose(self, input, output):
...         output[...] = input[:-1]
...     def reshapein(self, shapein):
...         return (shapein[0]+1,)
...     def reshapeout(self, shapeout):
...         return (shapeout[0]-1,)
...
>>> op = Op()
>>> op.shapein, op.shapeout
(None, None)
>>> op([1,2,3])
array([1, 2, 3, 0])
>>> op.T([1, 2, 3, 0])
array([1, 2, 3])
>>> np.array_equal(op.T.todense(4), op.todense(3).T)
True

### Operator with unconstrained input shape and implicit output shape

This operator can handle arbitrary inputs and its output dimensions are derived from those of the input. To obtain such operator, one simply has to define a reshapein method, which takes the input shape as input and returns the output shape. The following example stretches the input by a factor 2 along the first dimension.

>>> class Op(Operator):
...     def direct(self, input, output):
...         output[::2,...] = input
...         output[1::2,...] = input
...     def reshapein(self, shapein):
...         return (2*shapein[0],) + shapein[1:]
...
>>> op = Op()
>>> op.shapein, op.shapeout
(None, None)
>>> op.reshapein((2,3))
(4,3)
>>> op([[1, 2, 3],
...     [2, 3, 4]])
array([[1, 2, 3],
[1, 2, 3],
[2, 3, 4],
[2, 3, 4]])

### Operator with explicit input shape and unconstrained output shape

Such operator is obtained by only setting the shapein keyword. The following example fills the output with an arithmetic progression whose coefficients are given by the two elements of the input.

>>> class Op(Operator):
...     def __init__(self):
...         Operator.__init__(self, shapein=2)
...     def direct(self, input, output):
...         output[...] = input[0] + input[1] * np.arange(output.size).reshape(output.shape)
...
>>> op = Op()
>>> op.shapein, op.shapeout
((2,), None)
>>> y = np.empty((2,2), int)
>>> op([1, 2], out=y)
array([[1, 3],
[5, 7]])

### Operator with implicit input shape and unconstrained output shape

This kind of operator is of limited interest and is shown here for completeness. Since there is no way to compute the output shape from the input, the output argument must be provided. The operator in this example returns the input from which the last element has been removed.

>>> class Op(Operator):
...     def direct(self, input, output):
...         output[...] = input[:-1]
...     def reshapeout(self, shapeout):
...         return (shapeout[0] + 1,)
...
>>> op = Op()
>>> op.shapein, op.shapeout
(None, None)
>>> op([1,2,3])
ValueError: The output shape of an implicit input shape and unconstrained output shape operator cannot be inferred.
>>> y = np.empty(4)
>>> op([1.,2.,3.,4.,5.], out=y)
array([ 1.,  2.,  3.,  4.])
>>> op(np.arange(4.), out=y)
ValueError: The input has an invalid shape '(4,)'. Expected shape is '(5,)'.

### Operator with unconstrained input and output shape

This kind of operator is the default: this behaviour is obtained by not setting the shapein and shapeout keywords and not defining the reshapein and reshapeout methods. ConstantOperator is an example of such an operator. If the output is not provided as argument, it is assumed that the output shape is that of the input. The following example fills the output with the value of the sum of the elements of the input.

>>> class Op(Operator):
...     def __init__(self):
...         Operator.__init__(self)
...     def direct(self, input, output):
...         output[...] = np.sum(input)
...
>>> op = Op()
>>> op.shapein, op.shapeout
(None, None)
>>> y = np.empty((2,2), int)
>>> op([2, 1], out=y)
array([[3, 3],
[3, 3]])

## 2.7. Operator’s input and output shape validation.

It is possible to validate the shapes of the input or output of an operator by defining the validatein or validateout methods, which take the shapes of the input or output and raise a ValueError exception to signal a validation failure. There are two advantages of using these methods instead of performing the validation in the direct method:

• validation failures can be triggered earlier than the operator actual calling, for instance when the operators are combined in an expression
• the call to the validation methods can be optimised away when the operator is combined in an expression

The following example checks the number of axes and the dimension along the axes.

>>> class Op(Operator):
...     def direct(self, input, output):
...         output[...] = 1
...     def validatein(self, shapein):
...         if len(shapein) != 2:
...             raise ValueError('The number of axes of the input is not 2.')
...         if shapein[0] % 16 != 0 or shapein[1] % 16 != 0:
...             raise ValueError('The input dimensions are not a multiple of 16.')
...
>>> op = Op()
>>> op(np.ones(10))
ValueError: The number of axes of the input is not 2.
>>> op(np.ones(16,17))
ValueError: The input dimensions are not a multiple of 16.

## 2.8. Class propagation

An operator propagates the class of the input array, if the latter subclasses numpy.ndarray:

>>> class ndarray2(np.ndarray):
...     pass
>>> type(I(ndarray2((2,2))))
__main__.ndarray2

It is possible to change the subclass too, by using the classout keyword:

>>> class ndarray3(np.ndarray):
...     pass
>>> I2 = IdentityOperator(classout=ndarray3)
>>> type(I2(ndarray((2,2))))
__main__.ndarray3
>>> type(I2(ndarray2((2,2))))
__main__.ndarray3

## 2.9. Attribute propagation

An operator also propagates attributes:

>>> class ndarray2(np.ndarray):
...     pass
...
>>> x = ndarray2((2,2))
>>> x.foo = 'bar'
>>> I(x).foo
'bar'

It is also possible to add or change an attribute, by setting the attrout keyword to a dictionary whose keys are the attribute names and whose values are the attribute values:

>>> I2 = IdentityOperator(attrout={'foo':'new_bar'})
>>> I2(x).foo
'new_bar'
>>> x.foo
'bar'
>>> I2(np.ones((2,2))).foo
'new_bar'

More flexibility is possible by passing a function, instead of a dictionary, to the attrout keyword. This function expects a dictionary whose keys are the attribute names and whose values are the attribute values (it is the output’s __dict__):

>>> class I2Operator(IdentityOperator):
...     def __init__(self):
...         from time import ctime
...         if 'history' not in attr:
...             attr['history'] = []
...         attr['history'] += [ctime() + ' : ' + self.__class__.__name__]
...
>>> I2 = I2Operator()
>>> I2(I2(0)).history

## 2.10. Operator’s unary rules

The set of operators that can be obtained by using any number of times the '.C', '.T', '.H' and '.I' attributes over a given operator is finite. The set is made of the operator itself, its conjugate, transpose, adjoint, inverse, inverse-conjugate, inverse-transpose and inverse-adjoint.

It is possible to define such operators by using a unary rule of the form ‘subject’ is ‘predicate’. The subject being

 'C' operator’s conjugate 'T' operator’s transpose 'H' operator’s adjoint 'I' operator’s inverse 'IC' operator’s inverse-conjugate 'IT' operator’s inverse-transpose 'IH' operator’s inverse-adjoint

and the predicate being

 '.' the operator itself function callback function

For instance, the rule 'C''.' means that the operator’s conjugate is the operator itself. This is how the real decorator is translated internally. Likewise, the involutary decorator is represented by the rule 'I''.'.

Unary rules are attached to an operator by using the set_rule method:

>>> @pyoperators.flags.linear
... class Op1(Operator):
...     def __init__(self, **keywords):
...         Operator.__init__(self, **keywords)
...         self.set_rule('T', lambda s: ReverseOperatorFactory(Op2, s))
...     def direct(self, input, output):
...         output[:-1] = input
...         output[-1] = 0
...     def reshapein(self, shapein):
...         return (shapein[0]+1,)
...
>>> @pyoperators.flags.linear
... class Op2(Operator):
...     def __init__(self, **keywords):
...         Operator.__init__(self, **keywords)
...         self.set_rule('T', lambda s: ReverseOperatorFactory(Op1, s))
...     def direct(self, input, output):
...         output[...] = input[:-1]
...     def reshapein(self, shapein):
...         return (shapein[0]-1,)
...
>>> op1 = Op1()
>>> op2 = op1.T
>>> type(op2)
__main__.Op2
>>> array_equal(op1.todense(4), op2.todense(5).T)
True

The ReverseOperatorFactory is a convenience factory which returns an operator of the type its first argument and by swapping the attributes attrin(out), classin(out), shapein(out), reshapein(out), toshapein(out), validatein(out) from the second argument.

## 2.11. Operator’s binary rules

PyOperators has the ability to reduce arithmetic expressions involving operators. This is achieved by means of binary rules which are applied to pairs of operators. Such a rule is specific to an operation (addition, multiplication or composition) and has the form ‘subject1 \& subject2 → predicate’, in which subject1 and subject2 are properties that will be matched against the pair of actual operators. One of them must be ‘.’, and stands for the reference operator to which the rule is attached. For instance and for a given operator P, the subject ('.', '.') will match the pair (P, P), the subject ('T', '.') the pair (P.T, P) and ('.', 'H') the pair (P, P.H).
In addition to the subjects that can be used for unary rules, it is possible to specify an Operator subclass for subclass matching. For example the subject (‘.’, Operator) will match any Operator instance on the right of the reference operator.

When the pair of operators is matched by the subject, it is replaced by the predicate:

 '.' reference operator 'C' reference operator’s conjugate 'T' reference operator’s transpose 'H' reference operator’s ajoint 'I' reference operator’s inverse '1' identity operator function callback function

For a non-commutative operation (such as composition), the rules attached to the left-hand side operator applying on a right-hand-side operator are combined to the rules of the right-hand side operators applying on a left-hand-side operator:

• if one of the operator is a subclass of the other, its rules have higher priority
• otherwise, the rules of the right-hand side operator have higher priority

Rules attached to an operator are also prioritised:

• newer rules have higher priority
• non-matching-class rules have higher priority
• matching-class rules have a priority increasing with the depth of subclassing: the more specific the rule is, the higher priority it is.

Let’s examine some examples for the composition operation:

• ('T', '.')'1': if the expression P.T*P is matched, it will be replaced by the identity. This is how the orthogonal property is translated into a rule.
• ('.', 'I')'1': if the expression P*P.I is matched, it will be replaced by the identity.
• ('.', Operator)myfunc1: every time P appears as the left-hand-side operator of a pair, the callback function myfunc will be called and the pair of operators will be replaced by the result of this function, unless it is None, in which case the pair of operators is unchanged.

The rules attached to an operator are stored in the rules attribute. It is a dictionary whose keys can be AdditionOperator, CompositionOperator or MultiplicationOperator. For the non-commutative composition operation, rules are further split according to whether the operator is matched on the left or right hand side of the pair.
Rules are added by using the set_rule method, which has 3 arguments:

• the subject
• the predicate
• the operation (AdditionOperator, CompositionOperator, MultiplicationOperator)

The predicate can be a function, in which case it must be a static method with two arguments for the pair of operators that matches the subject. Rules, such as the ones set in the superclass, can be deleted with the del_rule method. In the following example, we construct an operator Power that raises its input to a specified power. We add a rule to reduce the composition of two instances of the Power class.

>>> @pyoperators.flags.square
... class Power(Operator):
...     def __init__(self, exponent):
...         Operator.__init__(self)
...         self.exponent = exponent
...         self.set_rule(('.', Power), self.rule_power, CompositionOperator)
...     def direct(input, output):
...         output[...] = input ** self.exponent
...     @staticmethod
...     def rule_power(p1, p2):
...         return Power(p1.exponent * p2.exponent)
...
>>> p1 = Power(2)
>>> p2 = Power(3)
>>> p = p1(p2)
>>> type(p)
__main__.Power
>>> p.exponent
6

## 2.12. In-place and out-of-place operators

in-place operator: operator whose direct method can handle input and output arguments pointing to the same memory location.

out-of-place operator: operator whose direct method cannot.

Such a property is set by the inplace decorator. For instance, the operator DiagonalOperator is an in-place operator and the following computation

>>> d = DiagonalOperator([1, 2])
>>> x = np.array([0, 1])
>>> d(x, x)
array([0, 2])

is done in-place and is equivalent to:

>>> x = np.array([0, 1])
>>> x *= [1, 2]

An in-place operator also has to handle out-of-place operations. In the following example, the operation is performed out-of-place to satisfy the no-side-effect policy:

>>> d = DiagonalOperator([1, 2])
>>> x = np.array([0, 1])
>>> y = d(x)
>>> y
array([0, 2])

which is equivalent to:

>>> x = np.array([0, 1])
>>> y = x * [1, 2]

The in-place property is useful to avoid intermediate variables. To minimise the memory-cache transfers during a composition, an algorithm has been put in place to determine the intermediate variables to be extracted from the memory manager, by maximising the temporal locality (i.e. by reusing as much as possible the same memory area). This algorithm depends on:

• the parity of the number of out-of-place operators
• whether or not the input and the output of the composition point the same memory location (in-place or out-of-place composition)
• the size of the output, and if it is large enough to be reused in the intermediate computations.

As an example, let’s consider the composition of an in-place operator IN by an out-of-place operator OUT. The out-of-place composition

>>> (IN * OUT)(x, out=y)

requires an intermediate variable only if the size of OUT ‘s output is larger than that of the y variable. Otherwise, y’s buffer is used as output for the OUT operator and the application of the operator IN is performed in-place on y.

Concerning the in-place composition:

>>> (IN * OUT)(x, out=x)

it is not possible to avoid the use of a temporary variable, since a buffer different from the x variable is required for the OUT operator. The application of the operator IN is performed out-of-place because its output is the x variable.

## 2.13. The flag update_output

Another possibility to avoid temporaries in the addition or element-wise multiplication of operators is to give an operator the possibility to directly update the running output argument in the direct method. It is particularly interesting for sums of matrices with few non-zero rows, since it gives a mechanism to skip the zero ones.
Let’s first see the default behaviour, in which the operands do not update their output argument:

>>> (o1 + o2)(x, out=y)

The following steps are performed:

• the buffer of variable y is used as o1 ’s output,
• a temporary buffer is allocated and used as o2 ’s output,
• which is then added in-place to y buffer.

If we now assume that the operator o2 can update its output argument, the intermediate variable is not required anymore:

• the buffer y is used as o1 ’s output
• and is passed as o2 ’s output argument to be updated in-place.

One can enable such property by adding the flag update_output and the keyword operation to the operator’s direct method.

>>> import operator
>>> import pyoperators
>>> from pyoperators import Operator, operation_assignment
>>> pyoperators.memory.verbose=True
>>> @pyoperators.flags.linear
... @pyoperators.flags.update_output
... class P(Operator):
...     def __init__(self, index):
...          self.index = index
...          Operator.__init__(self, shapein=1, shapeout=11)
...     def direct(self, input, output, operation=operation_assignment):
...         if operation is operation_assignment:
...             output[...] = 0
...         elif operation is not operator.iadd:
...             raise NotImplementedError()
...         output[self.index] += input
...
>>> Q = sum(P(i) for i in [0, 5, 10])
>>> y = np.empty(11)
>>> Q([2.], out=y)
array([ 2.,  0.,  0.,  0.,  0.,  2.,  0.,  0.,  0.,  0.,  2.])

No intermediate variable is needed and all operations are performed in-place. The AdditionOperator Q calls the direct method of its first operand P with the operation keyword set to the function operation_assignment, which means that P ‘s output should be assigned to the output argument. In the subsequent calls, the operation keyword is set to the iadd function from Python’s standard operator module (If Q were a MultiplicationOperator, it would be imul), which results in adding the operand’s output to the output argument in-place. This example shows the interest of the flag update_output when only few rows are non-zero: the output only need to be updated for these rows, which avoids thrashing the cache with zeros everytime an operand is called.

## 2.14. Operator partition

Currently, there are two ways to partition operators, depending on whether the partitioning is done in an already existing dimension or not.

 Stack partition: outputs are stacked along a new dimension Chunk partition: outputs are concatenated along an existing dimension

### Stack partition

A stack partition operator is an instance of BlockRowOperator initialised with the new_axisin keyword, BlockDiagonalOperator with the keywords new_axisin or new_axisout or BlockColumnOperator initialised with the new_axisout keyword. There is a strong constraint on the input and output shapes of the blocks, since they must be the same for all blocks. The partition along the specified axis is always explicit and is equal to a tuple of ones with as many elements as the number of blocks. In the following example is shown a stack partition block column operator:

>>> C = BlockColumnOperator([I, 2*I, 3*I], new_axisout=0)
>>> C(np.ones(2))
array([[ 1.,  1.],
[ 2.,  2.],
[ 3.,  3.]])

The outputs of the blocks are stacked along the dimension specified by new_axisout keyword, i.e the first one. The following example shows a stack partition block diagonal operator:

>>> D = BlockDiagonalOperator([I, 2*I, 3*I], new_axisin=-1)
>>> x = np.arange(2*3).reshape((2,3))
>>> x
array([[0, 1, 2],
[3, 4, 5]])
>>> D(x)
array([[ 0,  2,  6],
[ 3,  8, 15]])

It can be seen that the first block I is applied over x[:,0], the second block 2*I over x[:,1], and the third block 3*I over x[:,2].

### Chunk partition

A chunk partition operator can be obtained as an instance of BlockRowOperator initialised with the axisin keyword, BlockDiagonalOperator with the keywords axisin or axisout or BlockColumnOperator initialised with the axisout keyword. There is a lesser constraint on the shapes of the partitioned input and output of the blocks: all dimensions must be same except along the partitioned dimension(s). The partition along the specified axis can be implicit or explicit, which is reflected in the keywords partitionin and partitionout. The following example shows a block diagonal chunk partition operator with an explicit partition

>>> D = BlockDiagonalOperator([I, 2*I, 3*I], axisin=-1, partitionin=(2,3,2))
>>> D(np.ones(7))
array([ 1.,  1.,  2.,  2.,  2.,  3.,  3.])

It can be seen that the first block I is applied over the first two elements, the second block 2*I over the three following elements, and the third block 3*I over the last two elements. Block row and block column chunk partition operators can handle implicit partitions:

>>> C = BlockColumnOperator([I, 2*I, 3*I], axisout=-1)
>>> C(np.ones((2,2)))
array([[ 1.,  1.,  2.,  2.,  3.,  3.],
[ 1.,  1.,  2.,  2.,  3.,  3.]])

Likewise, the outputs of the blocks are concatenated along the dimension specified by the axisout keyword, i.e the last one in this case.

## 2.15. List of available operators

### Linear operators

• BandOperator
• ConvolutionOperator
• DegreesOperator
• DenseOperator
• DiagonalOperator
• DiagonalNumexprOperator
• DifferenceOperator
• EigendecompositionOperator
• FFTOperator
• HomothetyOperator
• IdentityOperator
• IntegrationTrapezeOperator
• PackOperator
• ReshapeOperator
• Rotation2dOperator
• Rotation3dOperator
• SparseOperator
• SumOperator
• SymmetricBandOperator
• SymmetricBandToeplitzOperator
• TridiagonalOperator
• UnpackOperator
• WaveletOperator
• Wavelet2dOperator
• ZeroOperator

### Non-linear operators

• ClipOperator
• Cartesian2SphericalOperator
• ConstantOperator
• HardThresholdingOperator
• MaxOperator
• MaximumOperator
• MinOperator
• MinimumOperator
• MinMaxOperator
• NormalizeOperator
• NumexprOperator
• PowerOperator
• ProductOperator
• ReciprocalOperator
• ReductionOperator
• RoundOperator
• SoftThresholdingOperator
• SqrtOperator
• SquareOperator
• Spherical2CartesianOperator
• To1dOperator
• ToNdOperator

### Composite operators

• BlockColumnOperator
• BlockRowOperator
• BlockDiagonalOperator
• BlockSliceOperator
• CompositionOperator
• GroupOperator
• MultiplicationOperator

### MPI operators

• MPIDistributionGlobalOperator
• MPIDistributionIdentityOperator

More operators can be found in the project PySimulators, projection, discrete differences, compression, downsampling, MPI operators, etc.
There is an on-going work consisting in migrating the most generic ones into the pyoperators package.

format: plain


text:
Today I cooked 24 pounds of sausage for breakfast
By lm (Sat Mar 25, 2006 at 02:39:59 PM EST) (all tags)
And I didn't eat any. Bits on Turks, coffee, Muslim brides and more follow.

Twelve your olds are interesting in many ways. When you watch movies with them they don't notice many of the same details and the things that are important to them don't necessarily have anything to do with the plot. For example, we watched Ron Howard's depression era boxing film Cinderella Man last night. I thought the story line was amazing. In the midst of the struggles of people starving in the street, families breaking apart, unemployment at twenty-five percent, a poor joe that wants to keep his family together returns to the boxing ring to buy milk and pay the electric bill ends up with the US heavyweight championship. In one scene, all the working class grunts from his neighborhood show up at the local Catholic parish to pray for him and listen to the heavyweight title match. In their minds, his fight is their fight, a common joe that's battling The Man and doing good despite the misery, Hoovervilles, job losses and broken families. So I asked my daughter if she understood why so many people turned out to the Church to pray for him. She thinks about it for a moment and replies, because they bet on him.''

The film really struck home with me. Many of the reenactments of the tragedies of the Great Depression caught me eye: the laborers lining up at the fence on the docks hoping beyond hope that they would get picked to work for the day, of families getting torn apart because they didn't have enough food to feed everyone, of ripping down wooden fences to burn to keep warm in the New Jersey winter because the electric and gas are both turned off due to nonpayment, not taking sick kids to the doctor because the last visit still isn't paid for, homeless guys living in shacks made of scrap wood in Central Park. In many countries throughout the world, people still face situations like these everyday and here I am on HuSi whining about the alienation I feel while getting paid to just slide by and do the least amount of work possible. I think its time for me to get my butt in gear and find some motivation.

The other thing that struck me is the difference in attitudes between the people in the bread lines as depicted in the movie compared to the people in bread lines today. If the movie was accurate (and books I've read and documentaries I've watched support the movies depiction) charity and public assistance was something that people were once ashamed to accept. A good number of people are still like that. If you watch the people in line there will be some that won't look you in the eye and fidget as if they are uncomfortable. Usually these people will be older, born two or three generations ago. Most of the people my age and younger don't seem disturbed that they're relying on charity. Not all, mind you, just most.

A good counter example is a friend of mine that has fallen on hard times. He's been looking for regular work for almost three years. Hiring managers tend to think that he's overqualified for most manual labor and service positions and don't give him the time of day. But the field his master's degree is in is highly competitive and he can't get his foot into the door. Another guy I know offered to help him out and was turned down. My friends has his pride and doesn't want charity. But that position seems to be a minority position whereas once it was the norm in the good old US of A.

Other things are changing in the US as well. A young lady from our parish converted to Islam back in December. Today my family went to observe her wedding ceremony. The aura of east meets west permeated the atmosphere in a rather disjointed fashion. The hall the ceremony was in was incredibly crafted with chandeliers, twenty foot mirrors lining the walls, oak trim and a bottom layer of concrete with a thin coat of paint and peeling wall paper with a stucco pattern. The ceremony was brief and had more the flavor of a legal proceeding than a religious ceremony despite being opened with chanting from Quran and a sermon. The reception was mostly segregated. Most of the Muslim men sat with other Muslim men and most of the Muslim women sat with other Muslim women. With a handful of exceptions, all of the tables with a mix of men and women were from the bride's Quaker family.

I found the chanting of the Quran to be the most beautiful part of the ceremony. Islamic chanting is heavily influenced by the octohedros of the Byzantine Churches.  These Byzantine tones and melodies, in turn, predate the Byzantine Churches by thousands of years. By the time of Plato and Aristotle, they were already ancient and divided into groups for which tone elicited which virtue so that educators could sing appropriated during the correct exercises to have the music reinforce the appropriate moral lesson. But let me clear, it isn't the Quran itself that I found beautiful, but the melody. Not comprehending Arabic, I wouldn't know if the cantor was chanting about how he wanted to cute me up into little pieces with a chain saw. It's the melody itself that has the power; these tones can change men's souls.

The other interesting part of the ceremony was the emphasis of the Islamic cleric on the God consciousness'' during the ceremony. I'm not certain of the Arabic term being translated such, but the English sounded quite a bit like Buddhism. But I am pretty certain that this impression is deceiving. I think it has more to do with the Platonic ideas of Islamic authors like Ibn Rush'd who postulated that the human intellect operates by participating in the Agent Intellect which is some sort of Overmind that emanates from the Godhead. On the other hand, succeeding generations of Muslims have declared such teaching to be heretical, so it's quite possible that the cleric didn't have Ibn Rush'd's teaching in mind either. But I'd be willing to wager that Ibn Rush'd is closer to what he had in mind than the Buddha nature.

The worst part of the whole shebang was the lack of coffee. Who would have ever thought that a Turk would have a wedding without having Turkish coffee served. Unfucking believable. Also, no water was served. Drinks were limited to cans of soda. The canned soda was quite a contrast to the chicken and lamb kabobs that were served for the main course. Baklava was also served. But no coffee.

This lack of coffee at wedding receptions, however, no longer extends to the evenings I'm on campus at the local community college learning to be a web monkey. After seven hard weeks of searching high and low through every building during class breaks, I finally found the single coffee vending machine on campus this past Wednesday. Few joys this past year have topped the feeling of a fifty-cent, shot of crappy espresso scalding my throat on the way down the hatch. Pure mother-fuckin' bliss.

Speaking of my night classes, there are only two weeks left in the quarter. The tech school I'm at divides the year into five quarters. (I don't think I'll be taking a math class from them.) Last night I registered for the new quarter which starts soon. The classes on the slate are a class offered by the art department (Design) and a class on mastering everybody's favorite monstrosity, Adobe Photoshop.

And that, my friends, is all.

Today I cooked 24 pounds of sausage for breakfast | 13 comments (13 topical, 0 hidden) | Trackback
Canned soda, by ambrosen (2.00 / 0) #1 Sat Mar 25, 2006 at 02:46:42 PM EST
seems to be the drink of choice at Islamic weddings. Or two litre bottles liberally strewn around. I've no idea why.

By best guess is that it is a misguided attempt... by lm (2.00 / 0) #2 Sat Mar 25, 2006 at 02:51:25 PM EST
... to get around the fact that the Quran forbids consumption of alcohol.

There is no more degenerate kind of state than that in which the richest are supposed to be the best.
Cicero, The Republic
[ Parent ]
five quarters by martingale (4.00 / 4) #3 Sat Mar 25, 2006 at 03:33:26 PM EST
Here's something you might enjoy. Take some flexible paper, and with a compass draw two (very) large nonoverlapping circles. In one circle, draw a single radius, in the other, mark a quarter (two radii). Now with scissors, cut out both circles, and cut along the radius for the first circle, and cut out the quarter from the second circle. Now use tape to attach the extra quarter to the first circle, to get a wobbly plate.

This is a model for a noneuclidean space with negative curvature. Take a pencil and a ruler, and draw some lines on it, making sure you never fold the paper and always keep the ruler tangent to it. See if nonparallel lines always intersect. Draw triangles in various places, and measure the sum of the angles. Finally, put it on your head and call it a party hat.
--
$E(X_t|F_s) = X_s,\quad t > s$

Turkish/Egyptian coffee by cam (2.00 / 0) #4 Sat Mar 25, 2006 at 03:48:45 PM EST
I work with a woman who is Egyptian, she has brought in Egyptian and Turkish coffee in the past. The kind you drink in special little cups. It pretty much blew my head off.
Aye, it does blow ones head off by lm (4.00 / 2) #6 Sat Mar 25, 2006 at 06:09:55 PM EST
Which is the point. Well, half the point. The other half is the flavor.

There is no more degenerate kind of state than that in which the richest are supposed to be the best.
Cicero, The Republic
[ Parent ]
Maslow's Hierarchy of Needs by clover kicker (4.00 / 1) #5 Sat Mar 25, 2006 at 06:00:39 PM EST
In many countries throughout the world, people still face situations like these everyday and here I am on HuSi whining about the alienation I feel while getting paid to just slide by and do the least amount of work possible.

People only worry about alienation when they're already warm and have full tummies.

We live in a very soft era, so we're soft people. If push comes to shove, I think most people could adapt and display tremendous fortitude/courage/grit. I'm lucky, I've rarely had to dig down to see how tough I am.

I read a article a few years ago, the author was remembering conversations with his dad about his cod-jigging days (fishing for cod with a hand-line in small boats). It was a hard life, the only detail I remember was when their fingers were completely numbed by the cold, they'd piss on their hands to get some feeling back.

His dad always said "You couldn't do it, b'y." And he's right, you need years of hard times to get to the point of working a job where pissing on your own hands improves the working conditions.

Don't feel bad/guilty that you worry about alienation, feel good that's all you have to worry about.

Yeah, I'm familiar with Maslow by lm (4.00 / 2) #7 Sat Mar 25, 2006 at 06:19:40 PM EST
Just so you know, I wasn't bringing up the fate of the downtrodden as an exercise in self-flagellation, but as an attempt to motivate myself to take action that is likely to keep my situation on the comfortable side of the have/have-not line.

There is no more degenerate kind of state than that in which the richest are supposed to be the best.
Cicero, The Republic
[ Parent ]
Curious by joh3n (2.00 / 0) #8 Sun Mar 26, 2006 at 06:34:09 AM EST
One can convert to Islam without repercussion, but convert from Islam, and you're supposed to be killed.

Isn't organized religion grand?

----

Kinda Like Scientology by CheeseburgerBrown (4.00 / 1) #10 Sun Mar 26, 2006 at 07:21:41 AM EST
Well, you have to admit ... by lm (2.00 / 0) #11 Sun Mar 26, 2006 at 03:59:32 PM EST
Islam wouldn't grow quite as fast if they killed off all of the converts to Islam.

There is no more degenerate kind of state than that in which the richest are supposed to be the best.
Cicero, The Republic
[ Parent ]
True by joh3n (2.00 / 0) #12 Sun Mar 26, 2006 at 04:02:11 PM EST
But they'd find a way to kill that person any way.

----

[ Parent ]
Chanting Soothes the Savage Beast by CheeseburgerBrown (2.00 / 0) #9 Sun Mar 26, 2006 at 07:19:37 AM EST
...Or baby, as the case may be (and is, for me -- I've been reading this entry in two sentence snippets as I walk around the room, stopping at my laptop once per lap, jiggling Baby Yam in time to Gregorian chanting being played on the stereo).

I initially had more to say, but let me boil it down to this: it's really hard to type with one hand.

(Baby now sleeping.)

I am from a small, unknown country in the north called Ca-na-da. We are a simple, grease-loving people who enjoy le weekend de ski.
I know that position all too well by lm (2.00 / 0) #13 Sun Mar 26, 2006 at 04:17:44 PM EST
Except when my tikes were that age, I was trying to post to a BBS forum rather than teh Intarweb.

There is no more degenerate kind of state than that in which the richest are supposed to be the best.
Cicero, The Republic
[ Parent ]
Today I cooked 24 pounds of sausage for breakfast | 13 comments (13 topical, 0 hidden) | Trackback