Julia – 39 – tipi – 8

Continuo da qui, copio qui.

Operazioni sui tipi
Since types in Julia are themselves objects, ordinary functions can operate on them. Some functions that are particularly useful for working with or exploring types have already been introduced, such as the <: operator, which indicates whether its left hand operand is a subtype of its right hand operand.

The isa() function tests if an object is of a given type and returns true or false:

The typeof() function, already used throughout the manual in examples, returns the type of its argument. Since, as noted above, types are objects, they also have types, and we can ask what their types are:

What if we repeat the process? What is the type of a type of a type? As it happens, types are all composite values and thus all have a type of DataType:

DataType is its own type.

Another operation that applies to some types is supertype(), which reveals a type’s supertype. Only declared types (DataType) have unambiguous supertypes:

If you apply supertype() to other type objects (or non-type objects), a MethodError is raised:

Visualizzazione su misura
Non so tradurre “Custom pretty-printing”.

Often, one wants to customize how instances of a type are displayed. This is accomplished by overloading the show() function. For example, suppose we define a type to represent complex numbers in polar form:

Unicode per Θ: 920, 0x398.

Here, we’ve added a custom constructor function so that it can take arguments of different Real types and promote them to a common type (see Constructors and Conversion and Promotion [prossimamente]). (Of course, we would have to define lots of other methods, too, to make it act like a Number, e.g. +, *, one, zero, promotion rules and so on.) By default, instances of this type display rather simply, with information about the type name and the field values, as e.g. Polar{Float64}(3.0,4.0).

If we want it to display instead as 3.0 * exp(4.0im), we would define the following method to print the object to a given output object io (representing a file, terminal, buffer, etcetera; see Networking and Streams [prossimamente]):

More fine-grained control over display of Polar objects is possible. In particular, sometimes one wants both a verbose multi-line printing format, used for displaying a single object in the REPL and other interactive environments, and also a more compact single-line format used for print() or for displaying the object as part of another object (e.g. in an array). Although by default the show(io, z) function is called in both cases, you can define a different multi-line format for displaying an object by overloading a three-argument form of show that takes the text/plain MIME type as its second argument (see Multimedia I/O [prossimamente]), for example:

Note that print(..., z) here will call the 2-argument show(io, z) method. This results in:

where the single-line show(io, z) form is still used for an array of Polar values. Technically, the REPL calls display(z) to display the result of executing a line, which defaults to show(STDOUT, MIME("text/plain"), z), which in turn defaults to show(STDOUT, z), but you should not define new display() methods unless you are defining a new multimedia display handler (see Multimedia I/O [prossimamente]).

Moreover, you can also define show methods for other MIME types in order to enable richer display (HTML, images, etcetera) of objects in environments that support this (e.g. IJulia). For example, we can define formatted HTML display of Polar objects, with superscripts and italics, via:

A Polar object will then display automatically using HTML in an environment that supports HTML display, but you can call show manually to get HTML output if you want:

An HTML renderer would display this as: Polar{Float64} complex number: 3.0e4.0i

:mrgreen:

SciPy – 54 – elaborazione di immagini multidimensionali – 6

Continuo da qui, copio qui.

Morfologia
morfologia binaria
The generate_binary_structure functions generates a binary structuring element for use in binary morphology operations. The rank of the structure must be provided. The size of the structure that is returned is equal to three in each direction. The value of each element is equal to one if the square of the Euclidean distance from the element to the center is less or equal to connectivity. For instance, two dimensional 4-connected and 8-connected structures are generated as follows:

Most binary morphology functions can be expressed in terms of the basic operations erosion and dilation.

  • The binary_erosion function implements binary erosion of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element as described in Filter functions [qui]. If no structuring element is provided, an element with connectivity equal to one is generated using generate_binary_structure. The border_value parameter gives the value of the array outside boundaries. The erosion is repeated iterations times. If iterations is less than one, the erosion is repeated until the result does not change anymore. If a mask array is given, only those elements with a true value at the corresponding mask element are modified at each iteration.
  • The binary_dilation function implements binary dilation of arrays of arbitrary rank with the given structuring element. The origin parameter controls the placement of the structuring element as described in Filter functions [stesso link]. If no structuring element is provided, an element with connectivity equal to one is generated using generate_binary_structure. The border_value parameter gives the value of the array outside boundaries. The dilation is repeated iterations times. If iterations is less than one, the dilation is repeated until the result does not change anymore. If a mask array is given, only those elements with a true value at the corresponding mask element are modified at each iteration.

Here is an example of using binary_dilation to find all elements that touch the border, by repeatedly dilating an empty array from the border using the data array as the mask:

The binary_erosion and binary_dilation functions both have an iterations parameter which allows the erosion or dilation to be repeated a number of times. Repeating an erosion or a dilation with a given structure n times is equivalent to an erosion or a dilation with a structure that is n-1 times dilated with itself. A function is provided that allows the calculation of a structure that is dilated a number of times with itself:

The iterate_structure function returns a structure by dilation of the input structure iteration-1 times with itself.

For instance:

If the origin of the original structure is equal to 0, then it is also equal to 0 for the iterated structure. If not, the origin must also be adapted if the equivalent of the iterations erosions or dilations must be achieved with the iterated structure. The adapted origin is simply obtained by multiplying with the number of iterations. For convenience the iterate_structure also returns the adapted origin if the origin parameter is not None:

Other morphology operations can be defined in terms of erosion and d dilation. The following functions provide a few of these operations for convenience:

  • The binary_opening function implements binary opening of arrays of arbitrary rank with the given structuring element. Binary opening is equivalent to a binary erosion followed by a binary dilation with the same structuring element. The origin parameter controls the placement of the structuring element as described in Filter functions [stesso link]. If no structuring element is provided, an element with connectivity equal to one is generated using generate_binary_structure. The iterations parameter gives the number of erosions that is performed followed by the same number of dilations.
  • The binary_closing function implements binary closing of arrays of arbitrary rank with the given structuring element. Binary closing is equivalent to a binary dilation followed by a binary erosion with the same structuring element. The origin parameter controls the placement of the structuring element as described in Filter functions [stesso link]. If no structuring element is provided, an element with connectivity equal to one is generated using generate_binary_structure. The iterations parameter gives the number of dilations that is performed followed by the same number of erosions.
  • The binary_fill_holes function is used to close holes in objects in a binary image, where the structure defines the connectivity of the holes. The origin parameter controls the placement of the structuring element as described in Filter functions [stesso link]. If no structuring element is provided, an element with connectivity equal to one is generated using generate_binary_structure.
  • The binary_hit_or_miss function implements a binary hit-or-miss transform of arrays of arbitrary rank with the given structuring elements. The hit-or-miss transform is calculated by erosion of the input with the first structure, erosion of the logical not of the input with the second structure, followed by the logical and of these two erosions. The origin parameters control the placement of the structuring elements as described in Filter functions [stesso link]. If origin2 equals None it is set equal to the origin1 parameter. If the first structuring element is not provided, a structuring element with connectivity equal to one is generated using generate_binary_structure, if structure2 is not provided, it is set equal to the logical not of structure1.

morfologia grey-scale
Grey-scale morphology operations are the equivalents of binary morphology operations that operate on arrays with arbitrary values. Below we describe the grey-scale equivalents of erosion, dilation, opening and closing. These operations are implemented in a similar fashion as the filters described in Filter functions [stesso link], and we refer to this section for the description of filter kernels and footprints, and the handling of array borders. The grey-scale morphology operations optionally take a structure parameter that gives the values of the structuring element. If this parameter is not given the structuring element is assumed to be flat with a value equal to zero. The shape of the structure can optionally be defined by the footprint parameter. If this parameter is not given, the structure is assumed to be rectangular, with sizes equal to the dimensions of the structure array, or by the size parameter if structure is not given. The size parameter is only used if both structure and footprint are not given, in which case the structuring element is assumed to be rectangular and flat with the dimensions given by size. The size parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be equal along each axis. The footprint parameter, if provided, must be an array that defines the shape of the kernel by its non-zero elements.

Similar to binary erosion and dilation there are operations for grey-scale erosion and dilation:

  • The grey_erosion function calculates a multidimensional grey- scale erosion.
  • The grey_dilation function calculates a multidimensional grey-scale dilation.

Grey-scale opening and closing operations can be defined similar to their binary counterparts:

  • The grey_opening function implements grey-scale opening of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale erosion followed by a grey-scale dilation.
  • The grey_closing function implements grey-scale closing of arrays of arbitrary rank. Grey-scale opening is equivalent to a grey-scale dilation followed by a grey-scale erosion.
  • The morphological_gradient function implements a grey-scale morphological gradient of arrays of arbitrary rank. The grey-scale morphological gradient is equal to the difference of a grey-scale dilation and a grey-scale erosion.
  • The morphological_laplace function implements a grey-scale morphological laplace of arrays of arbitrary rank. The grey-scale morphological laplace is equal to the sum of a grey-scale dilation and a grey-scale erosion minus twice the input.
  • The white_tophat function implements a white top-hat filter of arrays of arbitrary rank. The white top-hat is equal to the difference of the input and a grey-scale opening.
  • The black_tophat function implements a black top-hat filter of arrays of arbitrary rank. The black top-hat is equal to the difference of a grey-scale closing and the input.

:mrgreen:

Julia – 38 – tipi – 7

Continuo da qui, copio qui.

Tipi UnionAll
We have said that a parametric type like Ptr acts as a supertype of all its instances (Ptr{Int64} etc.). How does this work? Ptr itself cannot be a normal data type, since without knowing the type of the referenced data the type clearly cannot be used for memory operations. The answer is that Ptr (or other parametric types like Array) is a different kind of type called a UnionAll type. Such a type expresses the iterated union of types for all values of some parameter.

UnionAll types are usually written using the keyword where. For example Ptr could be more accurately written as Ptr{T} where T, meaning all values whose type is Ptr{T} for some value of T. In this context, the parameter T is also often called a “type variable” since it is like a variable that ranges over types. Each where introduces a single type variable, so these expressions are nested for types with multiple parameters, for example Array{T,N} where N where T.

The type application syntax A{B,C} requires A to be a UnionAll type, and first substitutes B for the outermost type variable in A. The result is expected to be another UnionAll type, into which C is then substituted. So A{B,C} is equivalent to A{B}{C}. This explains why it is possible to partially instantiate a type, as in Array{Float64}: the first parameter value has been fixed, but the second still ranges over all possible values. Using explicit where syntax, any subset of parameters can be fixed. For example, the type of all 1-dimensional arrays can be written as Array{T,1} where T.

Type variables can be restricted with subtype relations. Array{T} where T<:Integer refers to all arrays whose element type is some kind of Integer. The syntax Array{<:Integer} is a convenient shorthand for Array{T} where T<:Integer. Type variables can have both lower and upper bounds. Array{T} where Int<:T<:Number refers to all arrays of Numbers that are able to contain Ints (since T must be at least as big as Int). The syntax where T>:Int also works to specify only the lower bound of a type variable, and Array{>:Int} is equivalent to Array{T} where T>:Int.

Since where expressions nest, type variable bounds can refer to outer type variables. For example Tuple{T,Array{S}} where S<:AbstractArray{T} where T<:Real refers to 2-tuples whose first element is some Real, and whose second element is an Array of any kind of array whose element type contains the type of the first tuple element.

The where keyword itself can be nested inside a more complex declaration. For example, consider the two types created by the following declarations:

Type T1 defines a 1-dimensional array of 1-dimensional arrays; each of the inner arrays consists of objects of the same type, but this type may vary from one inner array to the next. On the other hand, type T2 defines a 1-dimensional array of 1-dimensional arrays all of whose inner arrays must have the same type. Note that T2 is an abstract type, e.g., Array{Array{Int,1},1} <: T2, whereas T1 is a concrete type. As a consequence, T1 can be constructed with a zero-argument constructor a=T1() but T2 cannot.

There is a convenient syntax for naming such types, similar to the short form of function definition syntax:

Vector{T} = Array{T,1}

This is equivalent to const Vector = Array{T,1} where T. Writing Vector{Float64} is equivalent to writing Array{Float64,1}, and the umbrella type Vector has as instances all Array objects where the second parameter – the number of array dimensions – is 1, regardless of what the element type is. In languages where parametric types must always be specified in full, this is not especially helpful, but in Julia, this allows one to write just Vector for the abstract type including all one-dimensional dense arrays of any element type.

Aliases di tipi
Sometimes it is convenient to introduce a new name for an already expressible type. This can be done with a simple assignment statement. For example, UInt is aliased to either UInt32 or UInt64 as is appropriate for the size of pointers on the system:

Su una macchina 32-bit il risultato sarebbe stato UInt32.

This is accomplished via the following code in base/boot.jl:

if Int === Int64
    const UInt = UInt64
else
    const UInt = UInt32
end

Of course, this depends on what Int is aliased to – but that is predefined to be the correct type – either Int32 or Int64.

Note that unlike Int, Float does not exist as a type alias for a specific sized AbstractFloat. Unlike with integer registers, the floating point register sizes are specified by the IEEE-754 standard. Whereas the size of Int reflects the size of a native pointer on that machine.

:mrgreen:

SciPy – 53 – elaborazione di immagini multidimensionali – 5

Continuo da qui, copio qui.

Filtri del dominio di Fourier
The functions described in this section perform filtering operations in the Fourier domain. Thus, the input array of such a function should be compatible with an inverse Fourier transform function, such as the functions from the numpy.fft module. We therefore have to deal with arrays that may be the result of a real or a complex Fourier transform. In the case of a real Fourier transform only half of the of the symmetric complex transform is stored. Additionally, it needs to be known what the length of the axis was that was transformed by the real fft. The functions described here provide a parameter n that in the case of a real transform must be equal to the length of the real transform axis before transformation. If this parameter is less than zero, it is assumed that the input array was the result of a complex Fourier transform. The parameter axis can be used to indicate along which axis the real transform was executed.

  • The fourier_shift function multiplies the input array with the multidimensional Fourier transform of a shift operation for the given shift. The shift parameter is a sequences of shifts for each dimension, or a single value for all dimensions.
  • The fourier_gaussian function multiplies the input array with the multidimensional Fourier transform of a Gaussian filter with given standard-deviations sigma. The sigma parameter is a sequences of values for each dimension, or a single value for all dimensions.
  • The fourier_uniform function multiplies the input array with the multidimensional Fourier transform of a uniform filter with given sizes size. The size parameter is a sequences of values for each dimension, or a single value for all dimensions.
  • The fourier_ellipsoid function multiplies the input array with the multidimensional Fourier transform of a elliptically shaped filter with given sizes size. The size parameter is a sequences of values for each dimension, or a single value for all dimensions. This function is only implemented for dimensions 1, 2, and 3.

No, niente esempi.

Funzioni di interpolazione
This section describes various interpolation functions that are based on B-spline theory. A good introduction to B-splines can be found in M. Unser, “Splines: A Perfect Fit for Signal and Image Processing,” IEEE Signal Processing Magazine, vol. 16, no. 6, pp. 22-38, November 1999.

pre-filtri per splines
Interpolation using splines of an order larger than 1 requires a pre-filtering step. The interpolation functions [here] described […] apply pre-filtering by calling spline_filter, but they can be instructed not to do this by setting the prefilter keyword equal to False. This is useful if more than one interpolation operation is done on the same array. In this case it is more efficient to do the pre-filtering only once and use a prefiltered array as the input of the interpolation functions. The following two functions implement the pre-filtering:

  • The spline_filter1d function calculates a one-dimensional spline filter along the given axis. An output array can optionally be provided. The order of the spline must be larger then 1 and less than 6.
  • The spline_filter function calculates a multidimensional spline filter.

Note: The multidimensional filter is implemented as a sequence of one-dimensional spline filters. The intermediate arrays are stored in the same data type as the output. Therefore, if an output with a limited precision is requested, the results may be imprecise because intermediate results may be stored with insufficient precision. This can be prevented by specifying a output type of high precision.

funzioni di interpolazione
Following functions all employ spline interpolation to effect some type of geometric transformation of the input array. This requires a mapping of the output coordinates to the input coordinates, and therefore the possibility arises that input values outside the boundaries are needed. This problem is solved in the same way as described in Filter functions [qui] for the multidimensional filter functions. Therefore these functions all support a mode parameter that determines how the boundaries are handled, and a cval parameter that gives a constant value in case that the ‘constant’ mode is used.

The geometric_transform function applies an arbitrary geometric transform to the input. The given mapping function is called at each point in the output to find the corresponding coordinates in the input. mapping must be a callable object that accepts a tuple of length equal to the output array rank and returns the corresponding input coordinates as a tuple of length equal to the input array rank. The output shape and output type can optionally be provided. If not given they are equal to the input shape and type.

For example:

Optionally extra arguments can be defined and passed to the filter function. The extra_arguments and extra_keywords arguments can be used to pass a tuple of extra arguments and/or a dictionary of named arguments that are passed to derivative at each call. For example, we can pass the shifts in our example as arguments

or

Note: The mapping function can also be written in C and passed using a scipy.LowLevelCallable. See Extending scipy.ndimage in C [prossimamente] for more information.

The function map_coordinates applies an arbitrary coordinate transformation using the given array of coordinates. The shape of the output is derived from that of the coordinate array by dropping the first axis. The parameter coordinates is used to find for each point in the output the corresponding coordinates in the input. The values of coordinates along the first axis are the coordinates in the input array at which the output value is found. (See also the numarray coordinates function.) Since the coordinates may be non- integer coordinates, the value of the input at these coordinates is determined by spline interpolation of the requested order.

Here is an example that interpolates a 2D array at (0.5, 0.5) and (1, 2):

The affine_transform function applies an affine transformation to the input array. The given transformation matrix and offset are used to find for each point in the output the corresponding coordinates in the input. The value of the input at the calculated coordinates is determined by spline interpolation of the requested order. The transformation matrix must be two-dimensional or can also be given as a one-dimensional sequence or array. In the latter case, it is assumed that the matrix is diagonal. A more efficient interpolation algorithm is then applied that exploits the separability of the problem. The output shape and output type can optionally be provided. If not given they are equal to the input shape and type.

The shift function returns a shifted version of the input, using spline interpolation of the requested order.

The zoom function returns a rescaled version of the input, using spline interpolation of the requested order.

The rotate function returns the input array rotated in the plane defined by the two axes given by the parameter axes, using spline interpolation of the requested order. The angle must be given in degrees. If reshape is true, then the size of the output array is adapted to contain the rotated input.

:mrgreen:

Julia – 37 – tipi – 6

Continuo da qui, copio qui.

Tipi Tuple
Tuples are an abstraction of the arguments of a function – without the function itself. The salient aspects of a function’s arguments are their order and their types. Therefore a tuple type is similar to a parameterized immutable type where each parameter is the type of one field. For example, a 2-element tuple type resembles the following immutable type:

However, there are three key differences:

  • Tuple types may have any number of parameters.
  • Tuple types are covariant in their parameters: Tuple{Int} is a subtype of Tuple{Any}. Therefore Tuple{Any} is considered an abstract type, and tuple types are only concrete if their parameters are.
  • Tuples do not have field names; fields are only accessed by index.

Tuple values are written with parentheses and commas. When a tuple is constructed, an appropriate tuple type is generated on demand:

Note the implications of covariance:

Intuitively, this corresponds to the type of a function’s arguments being a subtype of the function’s signature (when the signature matches).

Tuple tipo Vararg
The last parameter of a tuple type can be the special type Vararg, which denotes any number of trailing elements:

Notice that Vararg{T} corresponds to zero or more elements of type T. Vararg tuple types are used to represent the arguments accepted by varargs methods (see Varargs Functions [qui]).

The type Vararg{T,N} corresponds to exactly N elements of type T. NTuple{N,T} is a convenient alias for Tuple{Vararg{T,N}}, i.e. a tuple type containing exactly N elements of type T.

Tipi singleton
There is a special kind of abstract parametric type that must be mentioned here: singleton types. For each type, T, the “singleton type” Type{T} is an abstract type whose only instance is the object T. Since the definition is a little difficult to parse, let’s look at some examples:

In other words, isa(A,Type{B}) is true if and only if A and B are the same object and that object is a type. Without the parameter, Type is simply an abstract type which has all type objects as its instances, including, of course, singleton types:

Any object that is not a type is not an instance of Type:

Until we discuss Parametric Methods and conversions [prossimamente], it is difficult to explain the utility of the singleton type construct, but in short, it allows one to specialize function behavior on specific type values. This is useful for writing methods (especially parametric ones) whose behavior depends on a type that is given as an explicit argument rather than implied by the type of one of its arguments.

A few popular languages have singleton types, including Haskell, Scala and Ruby. In general usage, the term “singleton type” refers to a type whose only instance is a single value. This meaning applies to Julia’s singleton types, but with that caveat that only type objects have singleton types.

Tipi parametrici primitivi
Primitive types can also be declared parametrically. For example, pointers are represented as primitive types which would be declared in Julia like this:

The slightly odd feature of these declarations as compared to typical parametric composite types, is that the type parameter T is not used in the definition of the type itself – it is just an abstract tag, essentially defining an entire family of types with identical structure, differentiated only by their type parameter. Thus, Ptr{Float64} and Ptr{Int64} are distinct types, even though they have identical representations. And of course, all specific pointer types are subtypes of the umbrella Ptr type:

:mrgreen:

SciPy – 52 – elaborazione di immagini multidimensionali – 4

Continuo da qui, copio qui.

Funzioni filtro generiche
To implement filter functions, generic functions can be used that accept a callable object that implements the filtering operation. The iteration over the input and output arrays is handled by these generic functions, along with such details as the implementation of the boundary conditions. Only a callable object implementing a callback function that does the actual filtering work must be provided. The callback function can also be written in C and passed using a PyCapsule (see Extending scipy.ndimage in C [prossimamente] for more information).

The generic_filter1d function implements a generic one-dimensional filter function, where the actual filtering operation must be supplied as a Python function (or other callable object). The generic_filter1d function iterates over the lines of an array and calls function at each line. The arguments that are passed to function are one-dimensional arrays of the tFloat64 type. The first contains the values of the current line. It is extended at the beginning end the end, according to the filter_size and origin arguments. The second array should be modified in-place to provide the output values of the line. For example consider a correlation along one dimension:

The same operation can be implemented using generic_filter1d as follows:

Here the origin of the kernel was (by default) assumed to be in the middle of the filter of length 3. Therefore, each input line was extended by one value at the beginning and at the end, before the function was called.

Optionally extra arguments can be defined and passed to the filter function. The extra_arguments and extra_keywords arguments can be used to pass a tuple of extra arguments and/or a dictionary of named arguments that are passed to derivative at each call. For example, we can pass the parameters of our filter as an argument

or

The generic_filter function implements a generic filter function, where the actual filtering operation must be supplied as a Python function (or other callable object). The generic_filter function iterates over the array and calls function at each element. The argument of function is a one-dimensional array of the tFloat64 type, that contains the values around the current element that are within the footprint of the filter. The function should return a single value that can be converted to a double precision number. For example consider a correlation:

The same operation can be implemented using generic_filter as follows:

Here a kernel footprint was specified that contains only two elements. Therefore the filter function receives a buffer of length equal to two, which was multiplied with the proper weights and the result summed.

When calling generic_filter, either the sizes of a rectangular kernel or the footprint of the kernel must be provided. The size parameter, if provided, must be a sequence of sizes or a single number in which case the size of the filter is assumed to be equal along each axis. The footprint, if provided, must be an array that defines the shape of the kernel by its non-zero elements.

Optionally extra arguments can be defined and passed to the filter function. The extra_arguments and extra_keywords arguments can be used to pass a tuple of extra arguments and/or a dictionary of named arguments that are passed to derivative at each call. For example, we can pass the parameters of our filter as an argument

or

These functions iterate over the lines or elements starting at the last axis, i.e. the last index changes the fastest. This order of iteration is guaranteed for the case that it is important to adapt the filter depending on spatial location. Here is an example of using a class that implements the filter and keeps track of the current coordinates while iterating. It performs the same filter operation as described above for generic_filter, but additionally prints the current coordinates. Non sono riuscito a riprodurlo, mi da errori per range 😡

:mrgreen:

Julia – 36 – tipi – 5

Continuo da qui, copio qui.

Tipi parametrici astratti
Parametric abstract type declarations declare a collection of abstract types, in much the same way:

With this declaration, Pointy{T} is a distinct abstract type for each type or integer value of T. As with parametric composite types, each such instance is a subtype of Pointy:

Parametric abstract types are invariant, much as parametric composite types are:

The notation Pointy{<:Real} can be used to express the Julia analogue of a covariant type, while Pointy{>:Int} the analogue of a contravariant type, but technically these represent sets of types (see UnionAll Types [prossimamente]).

Much as plain old abstract types serve to create a useful hierarchy of types over concrete types, parametric abstract types serve the same purpose with respect to parametric composite types. We could, for example, have declared Point{T} to be a subtype of Pointy{T} as follows:

Given such a declaration, for each choice of T, we have Point{T} as a subtype of Pointy{T}:

This relationship is also invariant:

What purpose do parametric abstract types like Pointy serve? Consider if we create a point-like implementation that only requires a single coordinate because the point is on the diagonal line x = y:

Now both Point{Float64} and DiagPoint{Float64} are implementations of the Pointy{Float64} abstraction, and similarly for every other possible choice of type T. This allows programming to a common interface shared by all Pointy objects, implemented for both Point and DiagPoint. This cannot be fully demonstrated, however, until we have introduced methods and dispatch in the next section, Methods [prossimamente].

There are situations where it may not make sense for type parameters to range freely over all possible types. In such situations, one can constrain the range of T like so:

Nota: questa dichiarazione va in conflitto con le precedenti, per cui occorre chiudere e riaprire la REPL.

With such a declaration, it is acceptable to use any type that is a subtype of Real in place of T, but not types that are not subtypes of Real:

Type parameters for parametric composite types can be restricted in the same manner:

To give a real-world example of how all this parametric type machinery can be useful, here is the actual definition of Julia’s Rational immutable type (except that we omit the constructor here for simplicity), representing an exact ratio of integers:

It only makes sense to take ratios of integer values, so the parameter type T is restricted to being a subtype of Integer, and a ratio of integers represents a value on the real number line, so any Rational is an instance of the Real abstraction.

:mrgreen:

SICP – cap. 2 – painters – 62 – esercizi

Continuo da qui, copio qui.

Exercise 2.48: A directed line segment in the plane can be represented as a pair of vectors—the vector running from the origin to the start-point of the segment, and the vector running from the origin to the end-point of the segment. Use your vector representation from Exercise 2.46 [qui] to define a representation for segments with a constructor make-segment and selectors start-segment and end-segment.

Mi sembrava troppo semplice ma (sbirciando Bill the Lizard) è davvero così 😁

(define (make-segment v1 v2)
   (cons v1 v2))

(define (start-segment segment)
   (car segment))

(define (end-segment segment)
   (cdr segment))

sicp-ex, precede la stessa soluzione con heh, 👽
Stessa soluzione per Drewiki.

:mrgreen:

Visto nel Web – 300

Un pessimo periodo per tutto il mondo. Come ne verremo fuori?
Triste. Poi, al solito, ecco cosa ho wisto nel Web.

non solo quelli dell’Illinois

Eventually, Java will be Haskell. Circa 2050
#:linguaggi di programmazione
::: j0xaf

Better control your #Linux command line with GNU Screen
#:tools, componenti software
::: opensourceway

The NOVA filesystem
#:innovazioni, futuro
::: Donearm

Browser Extensions Are Undermining Privacy
#:sicurezza, spionaggio, virus
::: Slashdot

So. A lot of people are talking about this manifesto a Googler wrote a few days ago
ex-Googler shreds the internal manifesto
::: yonatanzunger ::: Slashdot

Build a Serverless Live Blog System with Flybase, Twilio and StdLib
#:Web, Internet
::: loige

Non solo Rousseau, R0gue_0 ha bucato anche BeppeGrillo.it e Il Blog delle Stelle
#:sicurezza, spionaggio, virus
::: DavidPuente

A US Spy Plane Has Been Flying Circles Over Seattle For Days
#:sicurezza, spionaggio, virus
::: Slashdot

Capro espiatorio
#:sicurezza, spionaggio, virus #:politica
::: Siamo Geek

The ‘haves and have-mores’ in digital America
#:economia
::: fabiochiusi

Bash process substitution
#:tip, suggerimenti
::: UnixToolTip

NodeWorker: an Electron alternative for the Internet of Things
#:Web, Internet #:linguaggi di programmazione
::: WebReflection

What programming language should I learn? (2017 edition)
#:linguaggi di programmazione
::: Adam Bard

Why Google Stores Billions of Lines of Code in a Single Repository
#:programming, codice, snippet
::: marcelsalathe

Google Fires Employee Behind Controversial Diversity Memo
#:ditte
::: stanveuger

Important questions for @tim_cook from @davidakaye on Apple’s censoring of VPN apps in China
#:censura
::: fabiochiusi

Anatomia emotiva dei grandi che dominano il web
#:Web, Internet
::: SergioGridelli

Journalists used machine learning to unmask secret surveillance flights inside the US
#:artificial intelligence
::: Snowden

Hands On With Manokwari, a GNOME Desktop Shell Built Using HTML5
#:tools, componenti software
::: dcavedon

You Can Trick Self-Driving Cars By Defacing Street Signs
#:artificial intelligence
::: Slashdot

Disney To Pull Its Movies From Netflix and Start Its Own Streaming Service
#:Web, Internet
::: Slashdot

TIL about the Eta programming language. Looks really cool 🙂
😊 uh! prepanico 👽
#:linguaggi di programmazione
::: lunaryorn

Google employee’s viral anti-diversity manifesto confirms your worst fears about tech-bro culture
#:programming, codice, snippet
::: Salon ::: Slashdot ::: Slashdot ::: fabiochiusi

Il tutto nel silenzio di Twitter, che si lascia usare come discarica di dati privati
#:sicurezza, spionaggio, virus
::: fabiochiusi

Editor performance when loading a 3GB file. Most tested editors literally cannot load the file
#:tools, componenti software
::: danluu

 

Zelo Innovativo
#:free open source software
::: MadBob

The New Copycats: How Facebook Squashes Competition From Startups
#_ditte
::: fabiochiusi

uLisp is now available for the Arduino Due, Arduino Zero, and Arduino MKRZero boards
#:lisp(s)
::: johnson_davies

In Less Than Five Years, 44 Trillion Cameras Will Be Watching Us
#:innovazioni, futuro
::: Slashdot

questo casca a fagiuolo per l’imminente release della nuova versione di GASdotto, completamente riscritta in Laravel
#:tools, componenti software
::: madbob

When your @Matlab license has expired and you realize that there is still @GnuOctave
::: Befedo

The Mozilla Information Trust Initiative: Building a movement to fight #misinformation online
chissà se…
::: phillipadsmith

Here’s what Google’s diversity and bias training looks like
#:ditte
::: fabiochiusi

Facebook è una palestra di normalizzazione della censura arbitraria. Perché siamo in 2 miliardi ad accettarla?
#:ditte
::: fabiochiusi

The GNOME Way
#:free open source software
::: lucaciavatta

I now consider every line of Go code I have ever written as deprecated code
#:linguaggi di programmazione
::: softmodeling ::: Symbo1ics

Python Data Science Handbook is a great book and even better reference guide
la nuova versione di quello che ho appena finito di studiare e copiare – raccomandatissimo
#:linguaggi di programmazione
::: mattayes

Happy bday to Apple co-founder Steve Wozniak
#:protagonisti
::: MIT_CSAIL

This is a major attack on privacy and freedom of expression online
#:censura
::: torproject

Startup To Put Cellphone Tower on the Moon
#:innovazioni, futuro
::: Slashdot

L’oggettività di #Wikipedia dipende da #NeutralitàDellaRete: operatori pronti a filtrare le fonti che non li pagano
#:Web, Internet
::: WikimediaItalia

Why Racket? Why Lisp?
#:lisp(s)
::: MartensJD

Sarahah l’app per scoprire come la pensano gli altri su di te
#:media #:applicazioni, programmi
::: la Stampa

MIT Team’s School-Bus Algorithm Could Save $5M and 1M Bus Miles
#:programming, codice, snippet
::: Slashdot

In China, Facebook Tests the Waters With a Stealth App
#:Web, Internet
::: fabiochiusi

25.000 #78giri preservati e digitalizzati: #InternetArchive sempre in grande!
#:storia
::: WikimediaItalia

This is an endless GIF that always shows the current time in UTC
#:programmazione funzionale
::: HookRace

System automatically retouches images like a professional photographer & can run on your phone
#:artificial intelligence
::: MIT_CSAIL

IBM introduced its PC #otd in 1981
#:storia
::: MIT_CSAIL

Julia – 35 – tipi – 4

Continuo da qui, copio qui.

Tipi composti mutabili
If a composite type is declared with mutable struct instead of struct, then instances of it can be modified:

In order to support mutation, such objects are generally allocated on the heap, and have stable memory addresses. A mutable object is like a little container that might hold different values over time, and so can only be reliably identified with its address. In contrast, an instance of an immutable type is associated with specific field values –- the field values alone tell you everything about the object. In deciding whether to make a type mutable, ask whether two instances with the same field values would be considered identical, or if they might need to change independently over time. If they would be considered identical, the type should probably be immutable.

To recap, two essential properties define immutability in Julia:

  • An object with an immutable type is passed around (both in assignment statements and in function calls) by copying, whereas a mutable type is passed around by reference.
  • It is not permitted to modify the fields of a composite immutable type.

It is instructive, particularly for readers whose background is C/C++, to consider why these two properties go hand in hand. If they were separated, i.e., if the fields of objects passed around by copying could be modified, then it would become more difficult to reason about certain instances of generic code. For example, suppose x is a function argument of an abstract type, and suppose that the function changes a field: x.isprocessed = true. Depending on whether x is passed by copying or by reference, this statement may or may not alter the actual argument in the calling routine. Julia sidesteps the possibility of creating functions with unknown effects in this scenario by forbidding modification of fields of objects passed around by copying.

Tpi dichiarati
The three kinds of types discussed in the previous three sections are actually all closely related. They share the same key properties:

  • They are explicitly declared.
  • They have names.
  • They have explicitly declared supertypes.
  • They may have parameters.

Because of these shared properties, these types are internally represented as instances of the same concept, DataType, which is the type of any of these types:

A DataType may be abstract or concrete. If it is concrete, it has a specified size, storage layout, and (optionally) field names. Thus a bits type is a DataType with nonzero size, but no field names. A composite type is a DataType that has field names or is empty (zero size).

Every concrete value in the system is an instance of some DataType.

Tipi unione
A type union is a special abstract type which includes as objects all instances of any of its argument types, constructed using the special Union function:

Tipi parametrici
An important and powerful feature of Julia’s type system is that it is parametric: types can take parameters, so that type declarations actually introduce a whole family of new types – one for each possible combination of parameter values. There are many languages that support some version of generic programming, wherein data structures and algorithms to manipulate them may be specified without specifying the exact types involved. For example, some form of generic programming exists in ML, Haskell, Ada, Eiffel, C++, Java, C#, F#, and Scala, just to name a few. Some of these languages support true parametric polymorphism (e.g. ML, Haskell, Scala), while others support ad-hoc, template-based styles of generic programming (e.g. C++, Java). With so many different varieties of generic programming and parametric types in various languages, we won’t even attempt to compare Julia’s parametric types to other languages, but will instead focus on explaining Julia’s system in its own right. We will note, however, that because Julia is a dynamically typed language and doesn’t need to make all type decisions at compile time, many traditional difficulties encountered in static parametric type systems can be relatively easily handled.

All declared types (the DataType variety) can be parameterized, with the same syntax in each case. We will discuss them in the following order: first, parametric composite types, then parametric abstract types, and finally parametric bits types.

Tipi parametrici composti
Type parameters are introduced immediately after the type name, surrounded by curly braces:

This declaration defines a new parametric type, Point{T}, holding two “coordinates” of type T. What, one may ask, is T? Well, that’s precisely the point of parametric types: it can be any type at all (or a value of any bits type, actually, although here it’s clearly used as a type). Point{Float64} is a concrete type equivalent to the type defined by replacing T in the definition of Point with Float64. Thus, this single declaration actually declares an unlimited number of types: Point{Float64}, Point{AbstractString}, Point{Int64}, etc. Each of these is now a usable concrete type:

The type Point{Float64} is a point whose coordinates are 64-bit floating-point values, while the type Point{AbstractString} is a “point” whose “coordinates” are string objects.

Point itself is also a valid type object, containing all instances Point{Float64}, Point{AbstractString}, etc. as subtypes:

Other types, of course, are not subtypes of it:

Concrete Point types with different values of T are never subtypes of each other:

Warning: This last point is very important: even though Float64 <: Real we DO NOT have Point{Float64} <: Point{Real}.

In other words, in the parlance of type theory, Julia’s type parameters are invariant, rather than being covariant (or even contravariant). This is for practical reasons: while any instance of Point{Float64} may conceptually be like an instance of Point{Real} as well, the two types have different representations in memory:

  • An instance of Point{Float64} can be represented compactly and efficiently as an immediate pair of 64-bit values;
  • An instance of Point{Real} must be able to hold any pair of instances of Real. Since objects that are instances of Real can be of arbitrary size and structure, in practice an instance of Point{Real} must be represented as a pair of pointers to individually allocated Real objects.

The efficiency gained by being able to store Point{Float64} objects with immediate values is magnified enormously in the case of arrays: an Array{Float64} can be stored as a contiguous memory block of 64-bit floating-point values, whereas an Array{Real} must be an array of pointers to individually allocated Real objects – which may well be boxed 64-bit floating-point values, but also might be arbitrarily large, complex objects, which are declared to be implementations of the Real abstract type.

Since Point{Float64} is not a subtype of Point{Real}, the following method can’t be applied to arguments of type Point{Float64}:

A correct way to define a method that accepts all arguments of type Point{T} where T is a subtype of Real is:

Equivalently, one could define function norm{T<:Real}(p::Point{T}) or function norm(p::Point{T} where T<:Real); see UnionAll Types [prossimamente].

More examples will be discussed later in Methods.

How does one construct a Point object? It is possible to define custom constructors for composite types, which will be discussed in detail in Constructors [prossimamente], but in the absence of any special constructor declarations, there are two default ways of creating new composite objects, one in which the type parameters are explicitly given and the other in which they are implied by the arguments to the object constructor.

Since the type Point{Float64} is a concrete type equivalent to Point declared with Float64 in place of T, it can be applied as a constructor accordingly:

For the default constructor, exactly one argument must be supplied for each field:

Only one default constructor is generated for parametric types, since overriding it is not possible. This constructor accepts any arguments and converts them to the field types.

In many cases, it is redundant to provide the type of Point object one wants to construct, since the types of arguments to the constructor call already implicitly provide type information. For that reason, you can also apply Point itself as a constructor, provided that the implied value of the parameter type T is unambiguous:

In the case of Point, the type of T is unambiguously implied if and only if the two arguments to Point have the same type. When this isn’t the case, the constructor will fail with a MethodError:

Constructor methods to appropriately handle such mixed cases can be defined, but that will not be discussed until later on in Constructors [prossimamente].

Pausa perché l’argomento è ancora lungo 😊

:mrgreen: