¿Cuáles son las bibliotecas de álgebra lineal / matemática / matricial lineal de C ++ más utilizadas, y sus compensaciones de costo y beneficio? [cerrado]

242

Parece que muchos proyectos surgen lentamente de la necesidad de hacer operaciones matemáticas de matriz, y caen en la trampa de construir primero algunas clases de vectores y agregar funcionalidades lentamente hasta que quedan atrapados construyendo una biblioteca de álgebra lineal personalizada a medias y dependiendo de ello.

Me gustaría evitar eso sin construir una dependencia de alguna biblioteca relacionada tangencialmente (por ejemplo, OpenCV, OpenSceneGraph).

¿Cuáles son las bibliotecas de álgebra lineal / matemática matricial comúnmente utilizadas y por qué decidir usar una sobre otra? ¿Hay alguna que se desaconseje usar por alguna razón? Estoy usando esto específicamente en un contexto geométrico / temporal * (2,3,4 Dim) * pero puede estar usando datos de dimensiones superiores en el futuro.

Estoy buscando diferencias con respecto a cualquiera de: API, velocidad, uso de memoria, amplitud / integridad, estrechez / especificidad, extensibilidad y / o madurez / estabilidad.

Actualizar

Terminé usando Eigen3 con el que estoy extremadamente feliz.

Catskul
fuente
2
Como mencionó OSG y OpenCV, supongo que solo necesita matrices / vectores de tipo de gráficos en 3D, es decir: matrices 3x3 y 4x4. Basé mi respuesta en eso, pero es posible que desee especificar exactamente cómo está usando esto: ¿necesita resolver la matriz? Matemáticas matriciales de dimensiones superiores? etc.
Reed Copsey
En este momento solo estoy haciendo cosas basadas en geometría 2D, pero hipotéticamente a veces necesitas operaciones 3x3 en datos 2D, y no está claro si los datos 3D y, por lo tanto, podrían ser necesarias operaciones 4x4. Nos gustaría utilizar una biblioteca común en toda la empresa. No tengo un buen sentido de lo que sería la compensación. Más general sería mejor, pero a qué costo es la pregunta.
Catskul
1
Si solo está haciendo transformaciones geométricas, realmente recomendaría mirar GGT, como mencioné en mi respuesta. Es muy completo para eso, pero realmente no hace nada PERO eso, por lo que es una opción muy limpia y fácil. BLAS y LAPACK son más para soluciones de matriz complejas de diseño (es decir: matrices de 50x50, matrices dispersas, etc.) para transformaciones científicas y matemáticas, no transformaciones geométricas.
Reed Copsey

Respuestas:

114

Hay bastantes proyectos que se han decidido por el Kit de herramientas de gráficos genéricos para esto. El GMTL allí es agradable: es bastante pequeño, muy funcional y se ha utilizado lo suficiente como para ser muy confiable. OpenSG, VRJuggler y otros proyectos han cambiado a usar esto en lugar de sus propias matemáticas de vértor / matriz enrolladas a mano.

Lo encontré bastante agradable: hace todo a través de plantillas, por lo que es muy flexible y muy rápido.


Editar:

Después de la discusión de comentarios y ediciones, pensé en arrojar más información sobre los beneficios y las desventajas de implementaciones específicas, y por qué podría elegir uno sobre el otro, dada su situación.

GMTL -

Beneficios: API simple, diseñada específicamente para motores gráficos. Incluye muchos tipos primitivos orientados a la representación (como planos, AABB, quatenrions con interpolación múltiple, etc.) que no están en ningún otro paquete. Muy poca carga de memoria, bastante rápido, fácil de usar.

Desventajas: API está muy centrada específicamente en renderizado y gráficos. No incluye matrices de propósito general (NxM), descomposición y resolución de matrices, etc., ya que están fuera del ámbito de las aplicaciones tradicionales de gráficos / geometría.

Eigen -

Beneficios: API limpia , bastante fácil de usar. Incluye un módulo de geometría con cuaterniones y transformaciones geométricas. Baja carga de memoria. Resolución completa y de alto rendimiento de grandes matrices NxN y otras rutinas matemáticas de propósito general.

Desventajas: puede ser un alcance un poco mayor de lo que deseas (?). Menos rutinas geométricas / de representación específicas en comparación con GMTL (es decir: definiciones de ángulo de Euler, etc.).

IMSL -

Beneficios: Biblioteca numérica muy completa. Muy, muy rápido (supuestamente el solucionador más rápido). Con mucho, la API matemática más grande y más completa. Comercialmente soportado, maduro y estable.

Desventajas: costo - no es barato. Muy pocos métodos geométricos / renderizados específicos, por lo que necesitará rodar los suyos sobre sus clases de álgebra lineal.

NT2 -

Beneficios: proporciona una sintaxis que es más familiar si está acostumbrado a MATLAB. Proporciona descomposición completa y resolución para matrices grandes, etc.

Desventajas: Matemáticas, no renderizadas. Probablemente no sea tan eficiente como Eigen.

LAPACK -

Beneficios: algoritmos muy estables y probados. He estado por mucho tiempo. Solución matricial completa, etc. Muchas opciones para matemáticas oscuras.

Desventajas: no es tan eficiente en algunos casos. Portado de Fortran, con API impar para su uso.

Personalmente, para mí, todo se reduce a una sola pregunta: ¿cómo planea usar esto? Si su enfoque es solo el renderizado y los gráficos, me gusta Generic Graphics Toolkit , ya que funciona bien y admite muchas operaciones útiles de renderizado sin tener que implementar el suyo. Si necesita una resolución de matriz de propósito general (es decir: SVD o LU descomposición de matrices grandes), iría con Eigen , ya que maneja eso, proporciona algunas operaciones geométricas y es muy eficiente con soluciones de matriz grande. Puede que necesite escribir más de sus propios gráficos / operaciones geométricas (encima de sus matrices / vectores), pero eso no es horrible.

Reed Copsey
fuente
¿Evaluó otras bibliotecas antes de decidirse por GMTL? La comparación superficial me llevó a creer que Eigen estaba mejor respaldado, pero eso se debe a la revisión de los sitios web respectivos. ¿Conoce alguna ventaja específica de uno sobre el otro?
Catskul
Eigen también funciona bien. No estaba tan maduro en el momento en que hice mi investigación, pero creo que sería una buena opción en este momento. GMTL se ha usado bastante ampliamente, y era muy maduro y sólido cuando decidí usarlo.
Reed Copsey
Supongo que para reducir mi pregunta al punto crucial: ¿Hiciste tu elección subjetivamente como "Esto se ve mejor" o donde hay características específicas (api, velocidad, uso de memoria, amplitud, estrechez, extensibilidad) que marcaron la diferencia. Supongo que la madurez cae bajo este criterio, pero si la madurez fuera la única métrica, imagino que habría seleccionado una opción basada en BLAS o LAPACK.
Catskul
Elegí esto después de probar varias opciones, y lo basé en: rendimiento, usabilidad y bajo tiempo de ejecución / sobrecarga de tiempo de compilación. Eigen se ve mucho mejor ahora que en ese momento, así que no puedo juzgar entre ellos. Sin embargo, estoy muy contento con GMTL para nuestros usos.
Reed Copsey
Eso es parte de por qué me gusta GMTL y lo usé. Simplemente se sintió muy natural de usar, y fue muy, muy fácil trabajar con él. También soportaba todo lo que necesitaba, en este caso, ya que solo estaba preocupado por manejar directamente la transformación geométrica y las rotaciones de cuaterniones.
Reed Copsey
38

Por lo tanto, soy una persona bastante crítica y creo que si voy a invertir en una biblioteca, será mejor que sepa en qué me estoy metiendo. Me imagino que es mejor criticar las críticas y menospreciar los halagos al escudriñar; lo que tiene de malo tiene muchas más implicaciones para el futuro que lo que está bien. Así que voy a ir un poco por la borda aquí para proporcionar el tipo de respuesta que me habría ayudado y espero que ayude a otros que puedan recorrer este camino. Tenga en cuenta que esto se basa en la poca revisión / prueba que he hecho con estas bibliotecas. Ah, y robé algunas de las descripciones positivas de Reed.

Mencionaré arriba que fui con GMTL a pesar de su idiosincrasia porque la inseguridad de Eigen2 era una desventaja demasiado grande. Pero recientemente he aprendido que la próxima versión de Eigen2 contendrá definiciones que cerrarán el código de alineación y lo harán seguro. Entonces puedo cambiar.

Actualización : me he cambiado a Eigen3. A pesar de su idiosincrasia, su alcance y elegancia son demasiado difíciles de ignorar, y las optimizaciones que lo hacen inseguro se pueden desactivar con una definición.

Eigen2 / Eigen3

Beneficios: LGPL MPL2, API limpia, bien diseñada, bastante fácil de usar. Parece estar bien mantenido con una comunidad vibrante. Baja carga de memoria. Alto rendimiento. Hecho para álgebra lineal general, pero también dispone de buena funcionalidad geométrica. Todo el encabezado lib, no se requiere enlace.

Idiocyncracies / inconvenientes: (Algunos / todos estos pueden evitarse mediante algunas definiciones que están disponibles en la rama de desarrollo actual Eigen3)

  • Las optimizaciones de rendimiento inseguras resultan en la necesidad de un seguimiento cuidadoso de las reglas. El incumplimiento de las reglas provoca accidentes.
    • simplemente no puede pasar de manera segura por valor
    • El uso de los tipos Eigen como miembros requiere una personalización especial del asignador (o se bloquea)
    • usar con tipos de contenedores stl y posiblemente otras plantillas requieren personalización de asignación especial (o se bloqueará)
    • ciertos compiladores necesitan cuidados especiales para evitar bloqueos en llamadas a funciones (ventanas GCC)

GMTL

Beneficios: LGPL, API bastante simple, diseñada específicamente para motores gráficos. Incluye muchos tipos primitivos orientados a la representación (como planos, AABB, quatenrions con interpolación múltiple, etc.) que no están en ningún otro paquete. Muy poca carga de memoria, bastante rápido, fácil de usar. Todo basado en encabezado, no es necesario vincular.

Idiocyncracies / inconvenientes:

  • API es peculiar
    • lo que podría ser myVec.x () en otra biblioteca solo está disponible a través de myVec [0] (problema de legibilidad)
      • una matriz o stl :: vector de puntos puede hacer que haga algo como puntosLista [0] [0] para acceder al componente x del primer punto
    • en un ingenuo intento de optimización, eliminó cross (vec, vec) y reemplazó con makeCross (vec, vec, vec) cuando el compilador elimina las temperaturas innecesarias de todos modos
    • las operaciones matemáticas normales no devuelven tipos normales a menos que apague algunas funciones de optimización, por ejemplo: vec1 - vec2no devuelve un vector normal, por lo que length( vecA - vecB )falla aunque vecC = vecA - vecBfuncione. Debes envolver como:length( Vec( vecA - vecB ) )
    • Las operaciones en vectores son proporcionadas por funciones externas en lugar de miembros. Esto puede requerir que use la resolución del alcance en todas partes ya que los nombres de símbolos comunes pueden colisionar
    • que tienes que hacer
        length( makeCross( vecA, vecB ) )
      o
        gmtl::length( gmtl::makeCross( vecA, vecB ) )
      donde podrías intentar
        vecA.cross( vecB ).length()
  • mal mantenido
    • todavía reclamado como "beta"
    • documentación que falta información básica como qué encabezados son necesarios para usar la funcionalidad normal
      • Vec.h no contiene operaciones para Vectores, VecOps.h contiene algunas, otras están en Generate.h, por ejemplo. cross (vec &, vec &, vec &) en VecOps.h, [make] cross (vec &, vec &) en Generate.h
  • API inmadura / inestable; sigue cambiando
    • Por ejemplo, "cross" se movió de "VecOps.h" a "Generate.h", y luego el nombre se cambió a "makeCross". Los ejemplos de documentación fallan porque todavía se refieren a versiones antiguas de funciones que ya no existen.

NT2

No puedo decirlo porque parecen estar más interesados ​​en el encabezado de la imagen fractal de su página web que en el contenido. Parece más un proyecto académico que un proyecto de software serio.

Último lanzamiento hace más de 2 años.

Aparentemente no hay documentación en inglés, aunque supuestamente hay algo en francés en alguna parte.

No puedo encontrar un rastro de una comunidad alrededor del proyecto.

LAPACK Y BLAS

Beneficios: Viejo y maduro.

Desventajas:

  • viejos como dinosaurios con API realmente malas
Catskul
fuente
1
Con respecto a las afirmaciones alineadas con Eigen: para obtener un alto rendimiento de las operaciones SSE (1,2,3 o 4) para pequeños conjuntos de datos, absolutamente necesita datos alineados. Las operaciones de carga / almacenamiento no alineadas son mucho más lentas. La decisión entre carga / almacenamiento alineado o no alineado también lleva tiempo. Cualquier implementación de "propósito general" tendría dificultades para hacer lo correcto para todos, a menos que también separen la interfaz en operaciones "alineadas" y "no alineadas", y de nuevo simplemente no es un propósito muy general.
Joris Timmermans
@Catskul Me gustaría usar Eigen3. ¿Podría ampliar "las optimizaciones que lo hacen inseguro se pueden desactivar con una definición"? Los otros problemas que enumera en Eigen2 se detallan cuidadosamente en el documento en Temas relacionados con problemas de alineación . Puedo vivir con estos problemas.
Ali
Los problemas de seguridad me refiero a todos los relacionados con la alineación y son los mismos del Eigen2. Si estás de acuerdo con Eigen2, estarás bien con Eigen3.
Catskul
2
BLAS y LAPACK no son en realidad bibliotecas sino especificaciones / API. podría haber mencionado sus implementaciones iniciales de netlib u otras implementaciones como ATLAS y OpenBLAS.
Foad
12

Por lo que vale, probé Eigen y Armadillo. A continuación se muestra una breve evaluación.

Ventajas de Eigen: 1. Completamente autónomo, sin dependencia de BLAS o LAPACK externos. 2. Documentación decente. 3. Supuestamente rápido, aunque no lo he puesto a prueba.

Desventaja: el algoritmo QR devuelve solo una matriz, con la matriz R incrustada en el triángulo superior. No tengo idea de dónde proviene el resto de la matriz, y no se puede acceder a ninguna matriz Q.

Ventajas del armadillo: 1. Amplia gama de descomposiciones y otras funciones (incluido QR). 2. Razonablemente rápido (usa plantillas de expresión), pero de nuevo, realmente no lo he llevado a grandes dimensiones.

Desventajas: 1. Depende de BLAS externo y / o LAPACK para descomposiciones de matriz. 2. Falta la documentación en mi humilde opinión (incluidos los detalles wrt LAPACK, aparte de cambiar una declaración #define).

Sería bueno si hubiera una biblioteca de código abierto disponible que sea autónoma y fácil de usar. Me he encontrado con este mismo problema durante 10 años, y se vuelve frustrante. En un momento, usé GSL para C y escribí envoltorios de C ++ a su alrededor, pero con C ++ moderno, especialmente usando las ventajas de las plantillas de expresión, no deberíamos tener que meternos con C en el siglo XXI. Solo mi tuppencehapenny.

Francis Urquhart
fuente
2
Armadillo tiene una sintaxis tipo Matlab deliberada, por lo que es fácil de usar. No estoy seguro de lo que quieres decir con "falta documentación ... especificaciones wP LAPACK". La documentación documenta claramente todas las funciones disponibles del usuario, junto con ejemplos de cómo usarlas. El punto completo acerca de una biblioteca de contenedor C ++ es abstraer la complejidad y la verbosidad de LAPACK. Siempre puede navegar por la fuente si desea ver cómo Armadillo llama a LAPACK.
mtall
Acerca de la descomposición QR en Eigen, ¿te refieres a Eigen2 o Eigen3?
qed
11

Si está buscando una matriz de alto rendimiento / álgebra lineal / optimización en procesadores Intel, miraría la biblioteca MKL de Intel.

MKL está cuidadosamente optimizado para un rendimiento rápido en tiempo de ejecución, en gran parte basado en los muy maduros estándares BLAS / LAPACK fortran. Y su rendimiento aumenta con la cantidad de núcleos disponibles. La escalabilidad de manos libres con núcleos disponibles es el futuro de la informática y no usaría ninguna biblioteca matemática para un nuevo proyecto que no sea compatible con procesadores de múltiples núcleos.

Muy brevemente, incluye:

  1. Operaciones básicas de vector-vector, vector-matriz y matriz-matriz
  2. Factorización matricial (descomposición LU, hermitiana, dispersa)
  3. Problemas de ajuste de mínimos cuadrados y valores propios
  4. Solucionadores de sistemas lineales dispersos
  5. Solucionador de mínimos cuadrados no lineales (regiones de confianza)
  6. Más rutinas de procesamiento de señales como FFT y convolución
  7. Generadores de números aleatorios muy rápidos (giro de Mersenne)
  8. Mucho más ... ver: texto del enlace

Una desventaja es que la API MKL puede ser bastante compleja dependiendo de las rutinas que necesita. También puede echar un vistazo a su biblioteca IPP (Integrated Performance Primitives) que está orientada a operaciones de procesamiento de imágenes de alto rendimiento, pero que, sin embargo, es bastante amplia.

Pablo

Software CenterSpace, bibliotecas de .NET Math, centerspace.net

Pablo
fuente
8

He escuchado cosas buenas sobre Eigen y NT2 , pero tampoco las he usado personalmente. También hay Boost.UBLAS , que creo que se está haciendo un poco largo en el diente. Los desarrolladores de NT2 están construyendo la próxima versión con la intención de ponerla en Boost, por lo que eso podría contar para algo.

Mi lin. alg. las necesidades no se extienden más allá del caso de la matriz 4x4, por lo que no puedo comentar sobre la funcionalidad avanzada; Solo estoy señalando algunas opciones.

Jeff Hardy
fuente
En mi experiencia (matrices más grandes), Boost.UBLAS se usa más. Sin embargo, cuando lo examiné, no me gustó (principalmente por la documentación), así que me concentré en Eigen. Eigen tiene un módulo de geometría , pero no lo he usado yo mismo.
Jitse Niesen
Al parecer, Eigen es utilizado por ROS (garaje de sauce), Celestia, Koffice y libmv. Veo algunas conversaciones sobre UBLAS, pero me costó encontrar proyectos que anuncien su uso. Lo mismo para NT2. ¿Puedes explicar qué cosas buenas has escuchado?
Catskul
Fue en una discusión en la lista de correo de Boost sobre la adición de una biblioteca moderna de LinAlg a Boost: Eigen y NT2 fueron mencionados como posibles candidatos, pero solo los desarrolladores de NT2 expresaron interés en continuar. Ambas bibliotecas parecían decentes; como dijiste, Eigen es un poco más popular, y también más C ++ - ish; NT2 está diseñado para imitar MATLAB tanto como sea posible.
Jeff Hardy
8

Soy nuevo en este tema, así que no puedo decir mucho, pero BLAS es prácticamente el estándar en informática científica. BLAS es en realidad un estándar API, que tiene muchas implementaciones. Sinceramente, no estoy seguro de qué implementaciones son más populares o por qué.

Si desea también poder realizar operaciones comunes de álgebra lineal (sistemas de resolución, regresión de mínimos cuadrados, descomposición, etc.), busque en LAPACK .

davidtbernal
fuente
7

¿Qué hay de GLM ?

Se basa en la especificación OpenGL Shading Language (GLSL) y se publica bajo la licencia MIT. Claramente dirigido a programadores gráficos

usuario3742582
fuente
bueno, proporciona vectores de programación de gráficos y matrices. introduce una buena cantidad de gastos generales para cumplir con GLSL (si puede hacerlo en GLSL, la mayoría de las veces hacerlo en GLSL es mejor, especialmente con GL 4.x), y se pierden muchas primitivas de programación de gráficos (frustum, AABB, BB, elipsoide ) Su interfaz swizzle es obesa. Una alternativa mucho mejor sería si tuviera funciones ".xyzz ()" generadas con alguna generación de código. Es perfecto cuando tienes que prototipar aplicaciones opengl y comienza a mostrar sus lados negativos en proyectos más grandes. nunca codifique una biblioteca matemática.
CoffeDeveloper
5

Agregaré voto para Eigen: porté una gran cantidad de código (geometría 3D, álgebra lineal y ecuaciones diferenciales) de diferentes bibliotecas a esta, mejorando tanto el rendimiento como la legibilidad del código en casi todos los casos.

Una ventaja que no se mencionó: es muy fácil de usar SSE con Eigen, que mejora significativamente el rendimiento de las operaciones 2D-3D (donde todo se puede rellenar a 128 bits).

ima
fuente
1
Todo el asunto "si haces esto, entonces asegúrate de ..." me parece una bandera roja. Hasta ahora me he encontrado con estos problemas dos veces y acabo de comenzar a usarlo. Realmente esperaba no molestar a los futuros desarrolladores por conocer todo tipo de idiosincrasias de cada biblioteca incluidas: específicamente los problemas de alineación donde se bloquea si no usa ciertas macros cada vez que tiene miembros, y el hecho de que han extendido la funcionalidad para cada individuo clases en múltiples encabezados. Solo puede que no me impida elegirlo, pero me ha enviado una señal de alerta.
Catskul
1
La alineación y esa macro solo son importantes si usa SSE, que de ninguna manera es necesario. Y si usa SIMD, esos problemas surgirán en cualquier biblioteca que use. Al menos Eigen no solo se bloquea, sino que proporciona mensajes de error significativos que apuntan directamente al problema.
ima
Y hay una manera fácil de evitar la macro de alineación: use punteros o referencias como miembros.
ima
1
No creo que sea verdad. No utilicé opciones especiales de SSE y tuve varios bloqueos después de usarlo con contenedores stl. Sí, sé que te da mensajes útiles, y sí, sé que hay instrucciones especiales, pero ese es mi punto. No quiero cargar a otros desarrolladores con instrucciones especiales para cada biblioteca incluida. Lo de no pasar por valor, por ejemplo, es demasiado.
Catskul
Me acabo de enterar de que la última rama de desarrollo tiene algunas definiciones que puede usar para desactivar la alineación y evitar los problemas relacionados.
Catskul
4

De acuerdo, creo que sé lo que estás buscando. Parece que GGT es una solución bastante buena, como sugirió Reed Copsey.

Personalmente, creamos nuestra propia pequeña biblioteca, porque nos ocupamos mucho de los puntos racionales, muchos NURBS y Béziers racionales.

Resulta que la mayoría de las bibliotecas de gráficos en 3D hacen cálculos con puntos proyectivos que no tienen base en matemáticas proyectivas, porque eso es lo que le da la respuesta que desea. Terminamos usando puntos de Grassmann, que tienen una base teórica sólida y disminuyeron el número de tipos de puntos. Los puntos de Grassmann son básicamente los mismos cálculos que la gente usa ahora, con el beneficio de una teoría sólida. Lo más importante es que aclara las cosas en nuestras mentes, por lo que tenemos menos errores. Ron Goldman escribió un artículo sobre puntos de Grassmann en gráficos por computadora llamado "Sobre los fundamentos algebraicos y geométricos de los gráficos por computadora" .

No directamente relacionado con su pregunta, pero una lectura interesante.

tfinniga
fuente
Es intencionalmente abierto porque no soy consciente de cuáles son las compensaciones. Probablemente sea justo decir que la geometría es nuestra principal preocupación, la dimensionalidad de la geometría no está clara. Actualmente es 2/3 (2 + tiempo) y podría ser hipotéticamente bastante alto (3dims + tiempo + multi-dim-costmaps).
Catskul
Estoy de acuerdo con la pregunta. Por ejemplo, muchas aplicaciones de este tipo necesitan rendimiento en tiempo real (comportamiento de tiempo constante), mientras que muchas otras están bien, ya que renuncian a la consistencia y / o velocidad para la precisión.
TED
Entonces, ¿estás diciendo que de las bibliotecas que investigaste, ninguna se ocupó de NURBS y Beziers? ¿Alguna razón en particular para no tomar una de las bibliotecas existentes y construir el soporte NURBS y Bezier junto a ella?
Catskul
Lo que intentaba decir es que NURBS y Beziers racionales usan puntos de control racional mucho más que la mayoría de las aplicaciones 3D, por lo que cometimos más errores. Por lo general, la mayoría de las aplicaciones 3D solo tienen puntos y vectores 3d vainilla hasta después de pasar por la transformación de perspectiva. Muchos de nuestros algoritmos tienen que ser capaces de manejar correctamente ponderada / puntos racionales / proyectivas y cartesianas, que van y vienen, etc.
tfinniga
0

Encontré esta biblioteca bastante simple y funcional ( http://kirillsprograms.com/top_Vectors.php ). Estos son vectores básicos implementados a través de plantillas C ++. Sin lujos, solo lo que necesita hacer con vectores (sumar, restar, multiplicar, punto, etc.).

Clark Gamble
fuente
1
A partir de diciembre de 2019, lamentablemente, el enlace está roto
10762409 dice Reinstate Monica el