Nothing
#' Symmetries of hyperplane arrangements define equivalent scales
#'
#' Produces scales of different colors which have equivalent scalar properties.
#' The hyperplane arrangements of MCT have three types of symmetry, which allows
#' us to find scales at different but equivalent points in the arrangement.
#' Such scales will be nearly structurally identical in most senses although
#' their specific intervals will be rather different. See details for a discussion
#' of the symmetries involved.
#'
#' Two symmetries of the MCT hyperplane arrangement are familiar.
#' One is modal "rotation":
#' two modes of the same scale must have equivalent structures, by the
#' defining relations of the theory. The parameter `b` controls these rotations.
#' The second familiar symmetry is *involution* (see "Modal Color Theory," 32).
#' Set parameter `involution` to TRUE to apply this symmetry. The more
#' interesting symmetry of the MCT arrangements is controlled by parameter `a`.
#' This symmetry allows us to permute the roles of the scale's generic intervals
#' in its scalar makeup. For instance, non-degenerate well-formed scales (see
#' [iswellformed()] are all generated by a particular generic interval. The
#' familiar diatonic scale is generated by its generic fourths, whereas
#' another well-formed scale like (0, 2, 3, 5, 6, 7, 9) in 10edo (with step-word
#' LSLSSLS) is generated by its generic sixths. We can permute the hyperplanes
#' of the heptachordal MCT arrangement so that the overall structure is
#' preserved but the diatonic scale is mapped onto LSLSSLS. In general, the
#' permutations of `ineqsym()` allow us to map any non-degenerate well-formed
#' scale onto any other: they form an orbit under the symmetries of the space.
#' This gives another sense in which "well-formedness" is a large family
#' of scale structures. That sense generalizes to *all* scales, not just ones
#' that are highly regular like well-formed scales.
#'
#' In short, `ineqsym()` preserves many scalar properties, including:
#' * [countsvzeroes()] and [svzero_fingerprint()]
#' * [howfree()]
#' * [ratio()], [delta()], and [eps()]
#' * [brightnessgraph()] structure
#' * [evenness()]
#' * [isgwf()] and *a fortiori* [iswellformed()]
#' * Number and respective properties of adjacent colors
#' * [spectrumcount()] up to permutation of the values
#'
#' @param set Numeric vector of pitch-classes in the set. Defaults to `NULL`, in which
#' case `card` must be specified.
#' @param a Integer: controls permutations of generic intervals. Must be
#' coprime to the size of the set. Defaults to `1`.
#' @param b Integer: controls modal rotation. Defaults to `0`.
#' @param card Integer: cardinality of the set to permute. Defaults to `NULL` and will
#' only be used if `set` is not entered.
#' @param involution Boolean: controls involutional symmetry. Defaults to
#' `FALSE`.
#' @inheritParams tnprime
#'
#' @returns Numeric vector representing a scale of same length as `set`.
#' Default parameters determine the identity symmetry and will return
#' `set` itself. If `set` is left as its default `NULL` value, the function returns
#' instead the `card`-by-`card` permutation matrix that implements the symmetry.
#'
#' @examples
#' wt_plus_1 <- sc(7,33)
#' equiv_scale <- ineqsym(wt_plus_1, 3, 2)
#' both_scales <- cbind(wt_plus_1, equiv_scale)
#' freedoms <- apply(both_scales, 2, howfree)
#' evennesses <- round(apply(both_scales, 2, evenness), 3)
#' svzeroes <- apply(both_scales, 2, countsvzeroes)
#' ratios <- round(apply(both_scales, 2, ratio), 3)
#' spectra <- apply(apply(both_scales, 2, spectrumcount), 2, toString)
#' cbind(freedoms, evennesses, svzeroes, ratios, spectra)
#' brightnessgraph(wt_plus_1)
#' brightnessgraph(equiv_scale)
#'
#' @export
ineqsym <- function(set=NULL,
a=1,
b=0,
card=NULL,
involution=FALSE,
edo=12) {
null_set <- is.null(set)
if (is.null(card)) {
if (null_set) {
stop("Set or card must be specified")
} else {
card <- length(set)
}
}
a <- a %% card
bad_a <- function() {
stop("Parameter a must be coprime to scale cardinality", call.=FALSE)
}
if (a == 0) {
bad_a()
}
permutation_matrix <- diag(card)
indices <- 0:(card-1)
indices <- ((a*indices)+b) %% card
indices <- indices + 1
permutation_matrix <- permutation_matrix[, indices]
if (involution) permutation_matrix <- -1 * permutation_matrix
if (qr(permutation_matrix)$rank < card) {
bad_a()
}
if (null_set) {
permutation_matrix
} else {
reset <- coord_to_edo(set, edo=edo)
res <- as.vector(permutation_matrix %*% reset)
coord_from_edo(res, edo=edo)
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.