Saltar al contenido

¿Cuáles son los requisitos para una variable indexada de buen comportamiento? ¿Subíndice, ToExpression, Downvalue?

Te traemos la respuesta a esta dificultad, al menos eso creemos. Si presentas preguntas coméntalo y sin tardanza

Solución:

Uso general

Esto es lo que pienso

  • Usando cadenas y posteriormente ToStringToExpression solo generar nombres de variables es bastante inaceptable, o al menos debería ser lo último que intente. No conozco un solo caso en el que esto no pueda reemplazarse con una mejor solución
  • El uso de subíndices también es bastante malo y debe evitarse, excepto con fines puramente de presentación, como señaló.
  • Para los casos en los que necesita utilizar muchas variables generadas, las variables indexadas suelen ser la mejor manera de hacerlo. Suelen tomar la forma

    head[index]
    

    y puede usarse en la mayoría de los lugares donde se pueden usar variables habituales, particularmente en ecuaciones u otras expresiones de naturaleza simbólica (inerte). Necesita un poco más de cuidado con las variables indexadas que con los símbolos simples, en particular, es mejor asegurarse de que index es numérico o, si es una expresión, debe ser inerte en el sentido de evaluación (mantener el mismo valor siempre o ningún valor).

  • A veces, también puede utilizar los símbolos generados mediante el uso de Unique[...]. Por lo general, se utilizan como marcadores de posición anónimos temporales en algunas transformaciones intermedias, pero luego deberá asegurarse de que se destruyan cuando ya no los necesite.

Asignaciones y estado

Un aspecto muy importante aquí es si las variables están destinadas a ser entidades simbólicas inertes o si planea almacenar algunos valores en ellas. A continuación, se indican algunas cosas a tener en cuenta:

  • Los valores almacenados en variables se almacenarán en diferentes tipos de reglas para variables de símbolo y variables indexadas:

    • Para las variables basadas en símbolos, estos estarán en OwnValues
    • Para las variables indexadas, estas estarán en DownValues, o algunas veces SubValues, si usa índices anidados.
  • Solo los símbolos permiten asignaciones de piezas. Entonces, por ejemplo, puedes hacer

    a = Range[10];
    a[[5]] = 100;
    

    pero no puedes hacer

    a[1]=Range[10]; (* Ok by itself *)
    a[1][[5]] = 100 (* Won't work *)
    

    Esto puede ser un gran problema para algunas aplicaciones.

  • Solo los símbolos pueden servir como variables / constantes locales en Module, Block, With, Function, Patternetc.

  • Para el caso de muchas variables, las variables indexadas pueden ser más fáciles de administrar, ya que solo debe borrar un símbolo.

  • Para borrar selectivamente una variable indexada dada, debe usar Unset, no Clear:

     a[1]=.
    
  • Las variables indexadas no se pueden usar dentro Compile, aunque puede aparecer que pueden.

  • Si debe realizar asignaciones a muchas variables (indexadas), consideraría usar un Association en lugar de. Esto puede facilitarlo desde el punto de vista de la gestión de recursos, ya que puede almacenar una asociación en una sola variable. Una ventaja adicional es que, entonces, se permiten asignaciones de partes a variables indexadas particulares:

    assoc = <|a -> 1, 2, 3, b -> 4, 5, 6|>;
    assoc[[Key[a], 2]] = 10;
    assoc
    
    (* <|a -> 1, 10, 3, b -> 4, 5, 6|> *)
    

Notas

Por lo que puedo recordar ahora, siendo AtomQ no es un requisito para la mayoría de los usos de variables. Siendo un llano Symbol se requiere en algunos casos, como para variables locales en construcciones de alcance, o asignaciones de partes, como expliqué anteriormente.

En general, mi experiencia es que la mayoría de los usos de las variables indexadas en el contexto de programación pura son más o menos equivalentes al uso de una tabla hash. En el contexto de las manipulaciones simbólicas, las variables indexadas pueden ser bastante útiles de muchas formas: pueden representar, por ejemplo, coeficientes de potencias en un polinomio y muchas otras cosas.

Para cualquier cosa que involucre programación / transformaciones, me mantendría alejado de Subscript, Notation`, Symbolize, y todas las demás cosas que pueden mezclar aspectos de evaluación y presentación. Usarlos en código es solo una invitación a problemas. Si desea formatear una expresión de alguna manera, escriba funciones especiales que lo harían, como una etapa separada.

Utilizando DownValues le permite formatear la pantalla en el formulario con subíndice sin usar Notation y Symbolize

(Format[#[n_]] := Subscript[#, n]) & /@ x, σ, a;

kvar[k_] := Through[x, σ, a[k]]

kvar[3]

ingrese la descripción de la imagen aquí

kvar[n]

ingrese la descripción de la imagen aquí

Si nunca va a utilizar un índice simbólico, puede restringir el argumento de kvar para Integer como lo hizo originalmente.

¿Cuáles son los requisitos para las variables de buen comportamiento?

Las funciones no son variables, aunque en la mayoría de los casos, el kernel trata las variables y funciones indefinidas de manera idéntica. A veces no es así. Después de todo, hay están lugares en matemáticas donde la diferencia entre un número y una función es importante.

Un ejemplo extremo e indocumentado es Dt[], la función derivada total. Allí,f[1] es muy diferente de f1. f[1] es un número, el valor de f en 1, constante por definición de una función matemática de una variable, mientras f1 no se supone que sea constante a menos que se haga una declaración explícita.

f[1]          f[1]

Head[f[1]]    f

AtomQ[f[1]]   False

Dt[f[x], x]   f'[x]

Dt[f[y], x]   Dt[y, x] f'[y]

Dt[f[1], x]   0

Dt[f1, x]     Dt[f1, x]

D[f[1], x]    0 

¿Cuál es la forma recomendada y más elegante de variables indexadas?

Un método muy simple es hacer esta definición para cada variable indexada:

x[i_Integer] := x[i] = With[u = Unique[x], Format[u] = Subscript[x, i]; u]

O,

 defineIndexedVariable[x_Symbol] := (
    x[i_Integer] := x[i] = With[u = Unique[x], Format[u] = Subscript[x, i]; u]
)

Permite subíndices negativos, no usa Symbol, y Unique[x] manejas Context correctamente, pero InputForm[Array[x,5]] impresiones (decir) x$2136, x$2152, x$2163, x$2164, x$2165. No hay tentación de escribir a veces x[1] y a veces escribir x$2136.

Otro método más complicado de construir símbolos sobre la marcha es bueno, no muy elegante, y es un ejemplo de cómo las cosas complicadas pueden colapsar repentinamente en la simplicidad, pero evita la repetición. string operaciones y problemas con $Context. Nos permite escribir v[1] y que se imprima como Subscript[v, 1] (que muestra $ text v _1 $) y tienen InputForm[v[1]], Head[v[1]], AtomQ[v[1]] evaluar a v⎵1, Symbol, True. InputForm[Array[v,5]] huellas dactilares v⎵1, v⎵2, v⎵3, v⎵4, v⎵5, y a veces podemos escribir v[1] y aveces v⎵1.

Simplemente pegue esta función en su cuaderno y evalúela para cada símbolo indexado. Cada subíndice entero no negativo evaluará la función del símbolo exactamente una vez. La primera versión evalúa el contexto[FUN]<> SymbolName[FUN] cada vez que se encuentra un nuevo subíndice.

defineIndexedVariable[FUN_Symbol] := 
FUN[ix_Integer /; ix ≥ 0] := With[
   v=Symbol[Context[FUN]<>SymbolName[FUN]<>"⎵"<>ToString[ix]]
,
   Format[v] = Subscript[FUN,ix];
   FUN[ix] = v
]

Para un símbolo, optimícelo a mano y especifique el contexto explícitamente en todas partes:

FUN`FUN[ix_Integer /; ix ≥ 0] := With[
   v=Symbol["FUN`FUN⎵"<>ToString[ix]]
,
   Format[v] = Subscript[FUN`FUN,ix];
   FUN`FUN[ix] = v
]

O obtenga la misma optimización con esta versión:

defineIndexedVariable[FUN_Symbol] := With[
   prefix = Context[FUN] <> SymbolName[FUN] <> "⎵"
,
   FUN[ix_Integer /; ix >= 0] := With[
        v = Symbol[prefix <> ToString[ix]]
    ,
        Format[v] = Subscript[FUN, ix];
        FUN[ix] = v
    ]
]

los Context[FUN] prefix asegura que todos los nuevos símbolos estarán en el mismo contexto que la definición de la función. los FUN[ix] = memoriza la función para Symbol se llama sólo una vez para cada índice distinto, y el Format[v] la definición se hace una sola vez. La ausencia de un punto y coma después del FUN[ix] = v es absolutamente esencial.

Después defineIndexedVariable[v], obtenemos (OutputForm en una terminal de texto)

                v
  v[1]           1

  Head[v[1]]    Symbol

  AtomQ[v[1]]   True

  Dt[v[x], x]   v'[x]

  Dt[v[y], x]   Dt[y, x] v'[y]

                Dt[v , x]
  Dt[v[1], x]       1

  Dt[v1, x]     Dt[v1, x]

  D[v[1], x]    0

Information["v"]:

Global`v

v[1] = v⎵1

v[ix$_Integer/;ix$>=0]:=With[v$=Symbol["Global`v⎵"<>ToString[ix$]],Format[v$]=Subscript[v,ix$];v[ix$]=v$]

Usando la interfaz estándar, ?? v no se muestrav⎵1. Pero InputForm[Array[x,5]] huellas dactilares v⎵1, v⎵2, v⎵3, v⎵4, v⎵5

Código que imprimió las tablas anteriores:

Function[x,Table["   ",Length[x]],HoldForm/@Unevaluated[x],x, HoldAll][v[1],InputForm[v[1]],Head[v[1]],AtomQ[v[1]],Dt[v[x],x],Dt[v[y],x],Dt[v[1],x],Dt[v1,x],D[v[1],x]]//Transpose//TableForm//Print

Si tienes alguna perplejidad y disposición de desarrollar nuestro post puedes ejecutar una explicación y con deseo lo observaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *