Archives pour la catégorie Scilab

Après GNU Octave 4.0.0, Scilab 6.0.0 se prépare à sortir

GNU Octave 4.0.0 est en effet sorti le 29 mai 2015 :

Octave 4.0 est une nouvelle version majeure avec de nombreuses nouvelles fonctionnalités, dont une interface utilisateur graphique, la prise en charge de la programmation orientée objet (classdef), une meilleure compatibilité avec MATLAB, et de nombreuses fonctions nouvelles et améliorées .

      → List of important user-visible changes

Scilab 6.0.0 (alpha) est sorti le 30 juillet 2015 :

Cette version inclut une réécriture majeure du noyau interne de Scilab. Les modifications apportées aux aspects visibles du logiciel sont limitées.

Ces changements n’auront pas beaucoup d’impact pour les utilisateurs finaux, mais ils apportent des améliorations majeures à la plateforme Scilab, qui conduiront à de nouvelles améliorations futures, en termes de gestion de code, d’outils de développement (débogueur, analyseur …), ainsi que des améliorations de Xcos, qui ne seraient pas possibles sans cette version.

      → Sortie de Scilab 6.0.0-alpha 1

À noter que Scilab 6 est encore en version alpha :

Comme toute alpha, cette version n’est encore pas prête pour être utilisée en production. Si vous débutez sur Scilab, ou si vous êtes un simple utilisateur, vous devriez continuer à utiliser la version 5.5.2, et attendre une version bêta avant d’essayer la famille 6.

Liens :

Voici donc deux nouvelles versions majeures pour les principaux concurrents de MATLAB en 2015 !

Utiliser Automation depuis Scilab sur Windows (2)

Dans un précédent billet, J’ai présenté une méthode permettant de faire communiquer Scilab et différent processus sur Windows : Utiliser Automation depuis Scilab sur Windows.

Avant de pouvoir utiliser le module « ole », il faut compiler des codes C++. Malheureusement, la compilation ne fonctionne pas avec les versions récentes de Visual Studio, notamment la version 12 (2013).

Compilation du module « ole »

Les étapes de la compilation sont résumées dans mon précédent billet  : Utiliser Automation depuis Scilab sur Windows.

Compilation réussie… ou pas ?

Pour savoir si le module « ole », a bien été correctement compilé, il faut vérifier deux choses.

D’une part, un nouveau dossier « bin » doit être créé. Il contient trois fichiers :

  • automation.dll
  • automation.exp
  • automation.lib

D’autre part, des fichiers avec l’extension « .bin » ont été créés dans le sous-dossier « macros »

Si c’est bien le cas, vous pouvez maintenant charger le module dans Scilab avec :

-->exec loader.sce;

Si vous obtenez le message :

!'VCExpress.exe' n'est pas reconnu en tant que commande interne   !
!                                                                 !
!ou externe, un programme exécutable ou un fichier de commandes.  !

Consultez le billet  : Utiliser Automation depuis Scilab sur Windows.

Si aucune erreur n’apparait et que les deux conditions énumérées précédemment ne sont pas vérifiées, il va falloir chercher où se situe le problème.

Échec de la compilation

Cherchez un fichier « automation.log » dans le sous-dossier « src\Release », ouvrez-le et cherchez le mot « error ». Vous avez maintenant un début de piste…

Si ce fichier « automation.log » n’existe pas ou que l’erreur ne correspond pas à celle décrite ci-dessous, ouvrez une nouvelle discussion dans le forum Scilab.

Erreur à l’inclusion de xtgmath.h

Avec Visual Studio 2013, une erreur apparait à la compilation de sci_ole_get.cpp (entre autres) :

1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2059: syntax error : '('
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2062: type 'double' unexpected
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2059: syntax error : ')'
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2027: use of undefined type 'std::enable_if'
                 C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtr1common(67) : see declaration of 'std::enable_if'
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): warning C4346: 'std::is_integral::value' : dependent name is not a type
                 prefix with 'typename' to indicate a type
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2062: type 'int' unexpected
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2146: syntax error : missing ')' before identifier '_Left'
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2146: syntax error : missing ';' before identifier '_Left'
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtgmath.h(206): error C2143: syntax error : missing ';' before '+'

La ligne 206 de « xtgmath.h » :

_GENERIC_MATH1(round, _CRTSPECIAL)

Rien d’anormal à première vue, sauf que « round » est une macro définie précédemment dans le fichier « core_math.h » de Scilab :

#define     round(a)    (int)(((a)<0.0)?(a)-.5:(a)+.5)

scilab-visual-studio-xtgmath
Solution rapide :

  • mettre en commentaire la ligne n°206 dans le fichier « xtgmath.h ». Le fichier est en lecture seule, vous devrez donc modifier ses propriétés directement depuis l’explorateur de Windows.
  • lancer à nouveau la compilation du module « ole » depuis Scilab
  • rétablir la ligne n°206 dans le fichier « xtgmath.h »

Ce n’est certes ni la solution la plus élégante, ni la solution la plus robuste, mais elle est relativement simple à mettre en Å“uvre.

Conclusion

J’espère que ces deux billets de blog vous permettront d’utiliser Automation depuis Scilab.

Si, malgré les solutions proposées, vous avez toujours des problèmes de compilation du module « ole », n’hésitez pas à ouvrir une nouvelle discussion dans le forum Scilab. Pensez à joindre le fichier « automation.log » si possible.

Scilab et le caractère NUL (0) dans les chaines de caractères

Hier, j’ai passé un bon moment à lutter avec Scilab et la lecture de données dans un fichier binaire. Au final, le problème venait de la présence du caractère ASCII NUL (valeur 0) dans la chaine de caractères que je lisais avec mgetstr.

Le problème présenté ici affecte la plupart des fonctions concernées : strindex, strcmp, strsubst, part, strtok…

Le problème

Utilisons la fonction strindex pour chercher l’indice du début d’un motif « def » dans une chaine de caractères « abcdef » :

str = "abcdef"

idx = strindex(str, "def")

Renvoi :

    4.

Ajoutons un espace, dont la valeur ASCII est 32, au début de la chaine précédente :

str = ascii(32) + str        // Ajout du caractère espace

idx = strindex(str, "def")

Renvoi :

    5.

Ajoutons une tabulation, dont la valeur ASCII est 8, au début de la chaine précédente :

str = ascii(8) + str        // Ajout du caractère tabulation

idx = strindex(str, "def")

Renvoi :

    6.

Aucun problème donc jusqu’ici.

Ajoutons maintenant le caractère NUL, dont la valeur ASCII est 0, au début de la chaine précédente :

str = ascii(0) + str        // Ajout du caractère NUL

idx = strindex(str, "def")

Renvoi :

     []

Aïe ! Aïe ! Aïe !

Le problème est identique avec d’autres fonctions :

part(str, 1)

 ans  =
 
     
 
part(str, 7)

 ans  =
 
     
 
part(str, 8)

 ans  =

L’explication

Les fonctions de Scilab qui traitent les chaines de caractères sont écrites en C. Or pour stocker une chaine de n caractères, il faut (au minimum) un tableau de n+1 éléments en langage C. Le dernier élément identifie la fin de la chaine de caractères. Et bien entendu, le caractère qui a été retenu pour remplir cette mission est le caractère NUL dont la valeur ASCII est 0 (voir la FAQ C à ce sujet).

Conséquence : si une chaine contient le caractère NUL (0), tous les caractères qui suivent seront ignorés.

Par exemple :

str = "hello world"

substr(1) = part(str, 1:5)
substr(2) = part(str, 7:$)

Renvoi :

!hello  !
!       !
!world  !

Alors que :

str = "hello" + ascii(0) + "world"

substr(1) = part(str, 1:5)
substr(2) = part(str, 7:$)

Renvoi :

!hello  !
!       !
!       !

Une solution

La solution consiste à remplacer le caractère NUL par un autre avant de traiter la chaine de caractères. Mais attention, il faudra impérativement remplacer la valeur numérique du caractère 0 par une autre (de 1 à 255) car nous avons vu précédemment que les fonctions Scilab n’avaient aucun effet.

str = "hello" + ascii(0) + "world"

 str  =
 
 hello world  
 
ascii(str)

 ans  =
 
    104.    101.    108.    108.    111.    0.    119.    111.    114.    108.    100.  
 
newStr = strsubst(str, 0, 32)
                              !--error 999
strsubst : Type erroné de l'argument d'entrée n°3 : Une chaîne de caractères attendue.
 
 
newStr = strsubst(str, ascii(0), ascii(32))

 newStr  =
 
 hello

Il faut donc faire la conversion implicitement :

numStr = ascii(str)

 numStr  =
 
    104.    101.    108.    108.    111.    0.    119.    111.    114.    108.    100.  
 
idx = numStr==0

 idx  =
 
  F F F F F T F F F F F  
 
numStr(idx) = 32 // par exemple

 numStr  =
 
    104.    101.    108.    108.    111.    32.    119.    111.    114.    108.    100.  
 
newStr = ascii(numStr)

 newStr  =
 
 hello world

Voila on peut maintenant gérer la chaine de caractères avec les fonctions Scilab :

substr(1) = part(newStr, 1:5)

 substr  =
 
!hello  !
!       !
!       !
 
substr(2) = part(newStr, 7:$)

 substr  =
 
!hello  !
!       !
!world  !
 
idx = strindex(newStr, "world")

 idx  =
 
    7.

Pourquoi mettre le caractère NUL dans une chaine de caractères ?

Quel est l’intérêt de mettre un caractère NUL dans une chaine ? J’aimerais pouvoir vous répondre : « aucun ». Mais j’ai mentionné la lecture de fichier tout au début de ce billet. Un fichier binaire peut contenir des valeurs numériques et des chaines de caractères.

Prenons l’exemple d’un fichier binaire contenant une valeur 0 suivie d’une chaine de caractères :

fd = mopen("test.dat", "wb")
mput(0, "uc", fd)
mput(ascii("hello world"), "uc", fd)
mclose(fd)

La lecture ne pose pas de problème particulier :

fd = mopen("test.dat", "rb")
str = mgetstr(12, fd)
mclose(fd)

Ce qui donne bien :

str

 str  =
 
  hello world  
 
ascii(str)

 ans  =
 
    0.    104.    101.    108.    108.    111.    32.    119.    111.    114.    108.    100.

Par contre :

idx = strindex(str, "world")

 idx  =
 
     []

Vous n’êtes pas convaincu par cet exemple trop simpliste, passons alors à un exemple pratique.

Validation de fichier DICOM

Les fichiers DICOM sont des fichiers binaires utilisés pour le stockage d’informations médicales. Ils contiennent des valeurs numériques et des chaines de caractères. Avant de lire un de ces fichiers, il est utile de tester sa validité. Le test le plus robuste consiste à chercher la chaine de caractères « 1.2.840.10008. » dans les premiers octets du fichier. La position de la chaine dans le fichier est inconnue et rien n’empêche que des valeurs nulles soient écrites avant…

La mauvaise solution :

fd = mopen("test.dcm", "rb")

buffer = mgetstr(2000, fd)
chk = strindex(buffer, "1.2.840.10008.")

if isempty(chk) then
    disp("Fichier non valide")
else
    disp("Fichier valide")
end

mclose(fd)

Le code ci-dessus renverra constamment « Fichier non valide » même si la chaine « 1.2.840.10008. » est bien présente dans le fichier.

La solution plus robuste à utiliser :

fd = mopen("test.dcm", "rb")

buffer = mgeti(2000, "uc", fd)
idx = buffer~=0
chk = strindex(ascii(buffer(idx)), "1.2.840.10008.")

if isempty(chk) then
    disp("Fichier non valide")
else
    disp("Fichier valide")
end

mclose(fd)

Dans cette version du code, les caractères NUL seront pris en compte avant de chercher la chaine « 1.2.840.10008. » Ce code fonctionne donc comme il faut.