#r "nuget: IKVM, 8.14.0"
#r "nuget: IKVM.Image, 8.14.0"- IKVM, 8.14.0
- IKVM.Image, 8.14.0
Serie Tweety - port C#/.NET natif (EPIC #4667). Ce notebook exploite le module
logics-rpclde TweetyProject sans JVM : la librairie Java est compilee vers un fat-jar Maven shade puis executee sur le runtime .NET via IKVM.
Navigation : Tweety-7a-Extended-Frameworks (argumentation etendue) - Tweety-7b-Ranking-Probabilistic-Csharp (ce notebook - RP-CL avec Maximum Entropy) - Tweety-8-Agent-Dialogues (dialogue multi-agents).
Ranking Probabilistic Conditional Logic (RP-CL) etend la logique conditionnelle (Tweety-3 CL) avec des probabilites sur les conditionnels relationnels (du premier ordre). Une formule RP-CL est de la forme :
(forall x. P(x) => Q(x)) [p]
ou p est une probabilite dans [0, 1] (Probability). Le problème de decision RP-CL est NP-difficile (combinaison ranking + FOL), et les raisonneurs RP-CL utilisent des techniques specialisees : Maximum Entropy (RpclMeReasoner), z-relations, et des sémantiques de ReferenceWorld.
Cas d’usage classiques : - Diagnostic medical : p(flu|fever) = 0.7, raisonner sur des chaînes causales avec incertitude. - Systèmes experts stochastiques : règles ponderees par probabilite, prediction sur des cas nouveaux. - Raisonnement defeasible probabiliste : CL + probabilites = si A alors B avec proba p, refute si exception. - Fusion d’informations : combiner plusieurs sources avec poids différents.
Dans ce notebook on manipule :
RelationalProbabilisticConditional (un conditionnel (B|A) avec une probabilite) ;RpclBeliefSet (ensemble de conditionnels probabilistes) ;RpclMeReasoner (Maximum Entropy - le plus performant) ;RpclSemantics (interface implementee par ReferenceWorld, etc.) ;RpclProbabilityDistribution (résultat = distribution de probabilite sur les mondes).logics-rpclOn installe le runtime IKVM, on fusionne l’image (base + arch), puis on charge la DLL org.tweetyproject.tweety-rpcl.dll (compilee cote build a partir d’un fat-jar shade embarquant logics-rpcl + ses dependances transitives : logics-rcl, logics-pcl, logics-pl, logics-commons, logics-fol, math, graphs, sat4j.core).
using System.IO;
// RID de la machine courante (win-x64, linux-x64, osx-arm64...) : IKVM.Image tire l'image native de chaque plateforme.
string ikvmVer = "8.14.0", ikvmRid = (OperatingSystem.IsWindows() ? "win" : OperatingSystem.IsMacOS() ? "osx" : "linux") + "-" + System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant();
string nugetRoot = Environment.GetEnvironmentVariable("NUGET_PACKAGES")
?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");
string ikvmBaseAny = Path.Combine(nugetRoot, "ikvm.image", ikvmVer, "ikvm", "any", "any");
string ikvmArchDir = Path.Combine(nugetRoot, "ikvm.image.runtime." + ikvmRid, ikvmVer, "ikvm", "any", ikvmRid);
string ikvmHome = Path.Combine(Path.GetTempPath(), "ikvm-home-" + ikvmVer + "-" + ikvmRid);
void IkvmCopyMerge(string src, string dst)
{
foreach (var d in Directory.GetDirectories(src, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(d.Replace(src, dst));
foreach (var f in Directory.GetFiles(src, "*", SearchOption.AllDirectories))
{
var t = f.Replace(src, dst);
Directory.CreateDirectory(Path.GetDirectoryName(t));
File.Copy(f, t, overwrite: true);
}
}
if (Directory.Exists(ikvmBaseAny) && Directory.Exists(ikvmArchDir))
{
Directory.CreateDirectory(ikvmHome);
IkvmCopyMerge(ikvmBaseAny, ikvmHome);
IkvmCopyMerge(ikvmArchDir, ikvmHome);
}
AppContext.SetData("IKVM.Home", ikvmHome);
Console.WriteLine("IKVM home=" + (File.Exists(Path.Combine(ikvmHome, "lib", "tzdb.dat")) ? "OK" : "MISSING"));IKVM home=OK
// Verification que la DLL chargee expose bien les classes RPCL cles.
using System.Reflection;
var tweetyDll = "org.tweetyproject.tweety-rpcl.dll";
var an = AssemblyName.GetAssemblyName(tweetyDll);
Console.WriteLine($"Tweety RPCL (IKVM) reference chargee : {an.Name} v{an.Version} ({new FileInfo(tweetyDll).Length / 1024 / 1024:F1} Mo).");Tweety RPCL (IKVM) reference chargee : org.tweetyproject.tweety-rpcl v1.30.0.0 (13.0 Mo).
#r "org.tweetyproject.tweety-rpcl.dll" charge bien la DLL (v1.30.0.0) - et depuis le correctif C190 (commit 6300d915, 2026-07-04 : IKVM 8.14 + shade downgrades en bytecode Java 8, meme fix que Tweety-3-ModalLogic-Csharp section 1.4), l’ancien diagnostic « GetTypes() retourne 0 type / bug IKVM 8.15 » est perime : re-mesure le 2026-09-28 sous le runtime epingle par ce notebook (IKVM 8.14.0), la DLL expose 7 697 types, dont 31 org.tweetyproject.logics.rpcl.*, avec les 6 types cles presents (RelationalProbabilisticConditional, RpclBeliefSet, RpclMeReasoner, RpclProbabilityDistribution, ReferenceWorld, AggregatingSemantics). La section 2 execute ci-dessous une construction RP-CL reelle sur cette DLL.
Verrou restant, mesure : la requete ME (RpclMeReasoner.query()) construit un probleme d’optimisation sous contraintes qu’aucun solveur general embarque ne couvre (NLCG : problemes sans contraintes ; CMAES : contraintes de bord seulement ; Gurobi : licence + bibliotheque native absente). Sans solveur par defaut configure, l’appel termine meme le process (« No default solver for general optimization problems configured ») ; la section 4 le demontre en configurant un solveur puis en interceptant son refus reel.
Portee du verdict : la partie syntaxe/construction est verifiee par execution (section 2) ; la boucle ME reste bloquee - verrou mesure, chemin de sortie non verifie : pistes non testees ici (un solveur sous contraintes tel que Gurobi, si sa licence et sa bibliotheque native sont disponibles ; ou une recompilation du shade - recette dotnet-build/build-TweetyRpclShade.csproj). Aucune de ces pistes n’a ete demontree. En attendant, l’ancien code des sections 3-4 reste conserve en commentaire sous les cellules reecrites ; sa reactivation exigera une reecriture partielle (l’API citee y est inexacte : FolPredicate n’existe pas en 1.30 - le vrai type est commons.syntax.Predicate ; les variables doivent commencer par une majuscule ; Probability exige un java.lang.Double). Les exercices utilisent la vraie API RP-CL, dont les types sont bien exposes ; seule leur boucle ME complete depend de la levee du verrou solveur.
Une formule RP-CL est un conditionnel relationnel probabiliste :
(forall x. P(x) => Q(x)) [0.8]
Cela signifie : pour tout individu x, si P(x) est vrai, alors Q(x) est vrai avec probabilite 0.8.
Trois constructeurs principaux : - RelationalProbabilisticConditional(premise, conclusion, probability) : forme générale ; - RelationalProbabilisticConditional(premise, conclusion) : probabilite par defaut = 1.0 ; - RelationalProbabilisticConditional(relationalConditional, probability) : a partir d’un conditionnel déjà construit.
Le complement Tweety d’un conditionnel (B|A)[p] est le meme conditionnel avec la probabilite 1-p (mesure en section 2 : (flu(a)|fever(a))[0.3] pour p = 0.7).
Cas pedagogique canonique : le diagnostic medical. - fever => flu avec probabilite 0.7 : si le patient a de la fievre, il a la grippe avec 70% de chance. - Question : quelle est la probabilite que le patient ait la grippe ? RpclMeReasoner.query(...) repond.
// Construction REELLE d'une base RP-CL sur la DLL chargee (API Tweety 1.30, verifiee) :
// Predicate(nom, arite) et Constant(nom). L'API citee par l'ancien bloc conserve ci-dessous
// etait inexacte : FolPredicate inexistant, variable minuscule rejetee, Probability(double) introuvable.
using Pred = org.tweetyproject.logics.commons.syntax.Predicate;
using FolAtom = org.tweetyproject.logics.fol.syntax.FolAtom;
using RpcCond = org.tweetyproject.logics.rpcl.syntax.RelationalProbabilisticConditional;
var fever = new Pred("fever", 1);
var flu = new Pred("flu", 1);
var cold = new Pred("cold", 1);
var a = new org.tweetyproject.logics.commons.syntax.Constant("a");
var A_fever = new FolAtom(fever, a);
var A_flu = new FolAtom(flu, a);
var A_cold = new FolAtom(cold, a);
// Base medicale a un patient (constante "a") : R1 fever=>flu [0.7], R2 fever=>cold [0.5], R3 flu=>!cold [0.8].
var bs = new org.tweetyproject.logics.rpcl.syntax.RpclBeliefSet();
bs.add(new RpcCond(A_fever, A_flu, new org.tweetyproject.math.probability.Probability(java.lang.Double.valueOf(0.7))));
bs.add(new RpcCond(A_fever, A_cold, new org.tweetyproject.math.probability.Probability(java.lang.Double.valueOf(0.5))));
bs.add(new RpcCond(A_flu, new org.tweetyproject.logics.fol.syntax.Negation(A_cold), new org.tweetyproject.math.probability.Probability(java.lang.Double.valueOf(0.8))));
Console.WriteLine($"Base RP-CL construite : {bs.size()} conditionnels probabilistes.");
var r1 = new RpcCond(A_fever, A_flu, new org.tweetyproject.math.probability.Probability(java.lang.Double.valueOf(0.7)));
Console.WriteLine($"Conditionnel canonique : {r1}");
Console.WriteLine($"Probabilite : {r1.getProbability()}");
Console.WriteLine($"Complement (meme conditionnel, p -> 1-p) : {r1.complement()}");
// --- Ancien code original, conserve pour reference historique (API inexacte, non reactivable tel quel) ---
// La DLL tweety-rpcl.dll expose 0 types `org.tweetyproject.logics.*`
// alors que le JAR shade contient toutes les classes. Bug IKVM 8.15 sur JAR shades
// avec deps transitives. Sibling PL (Tweety-2c-FOL) OK.
//
// // Construire un conditionnel probabiliste canonique : fever => flu [0.7].// // Syntaxe : (forall x. P(x) => Q(x)) [p] = RelationalProbabilisticConditional(premise, conclusion, Probability).// using org.tweetyproject.logics.fol.syntax;// using org.tweetyproject.logics.rpcl.syntax;// using org.tweetyproject.math.probability;//// // Predicats : fever(x), flu(x).// var fever = new FolPredicate("fever");// var flu = new FolPredicate("flu");// var x = new org.tweetyproject.logics.commons.syntax.Variable("x");// // Premisse : fever(x). Conclusion : flu(x).// var premise = new FolAtom(fever, x);// var conclusion = new FolAtom(flu, x);// // Probabilite : 0.7.// var prob = new Probability(0.7);// // Conditionnel probabiliste.// var cond = new RelationalProbabilisticConditional(premise, conclusion, prob);// Console.WriteLine($"Conditionnel RP-CL : {cond}");// Console.WriteLine($"Probabilite : {cond.getProbability()}");// Console.WriteLine($"Complement : {cond.complement()}");//Base RP-CL construite : 3 conditionnels probabilistes.
Conditionnel canonique : (flu(a)|fever(a))[0.7]
Probabilite : 0.7
Complement (meme conditionnel, p -> 1-p) : (flu(a)|fever(a))[0.30000000000000004]
RpclBeliefSet est un ensemble de conditionnels probabilistes partageant une FolSignature. Le raisonneur de reference est RpclMeReasoner (ME = Maximum Entropy) : il cherche la distribution de probabilite sur les mondes possibles (interpretations FOL) qui maximise l’entropie tout en satisfaisant les contraintes RP-CL.
Pourquoi Maximum Entropy ? La distribution ME est celle qui maximise l’entropie de Shannon H(P) = -Σ P(w) log P(w) sur les mondes possibles, sous les contraintes des conditionnels. C’est le principe de Jaynes (1957) : parmi toutes les distributions compatibles, choisir la moins informative —
Deux modes d’inference : - STANDARD_INFERENCE (defaut) : enumeration classique des mondes. - LIFTED_INFERENCE : inference lifted (au niveau des classes d’equivalence plutot que des instances).
// Diagnostic exact, EXECUTE : les types ME sont bien charges - c'est le solveur d'optimisation
// sous contraintes qui manque dans le shade, pas l'exposition des types (verdict section 1).
using System.Linq;
var rpclAsm = AppDomain.CurrentDomain.GetAssemblies().First(x => x.GetName().Name == "org.tweetyproject.tweety-rpcl");
var tweetyTypes = rpclAsm.GetTypes();
Console.WriteLine($"Types org.tweetyproject.logics.rpcl.* charges : {tweetyTypes.Count(t => t.FullName!.StartsWith("org.tweetyproject.logics.rpcl."))}");
foreach (var k in new[] { "RelationalProbabilisticConditional", "RpclBeliefSet", "RpclMeReasoner", "RpclProbabilityDistribution", "ReferenceWorld", "AggregatingSemantics" })
Console.WriteLine($" {k,-40} {(tweetyTypes.Any(t => t.Name == k) ? "PRESENT" : "ABSENT")}");
var solvers = tweetyTypes.Where(t => t.FullName!.StartsWith("org.tweetyproject.math.opt.solver.") && !t.FullName.Contains("+")).Select(t => t.Name).OrderBy(n => n).ToList();
Console.WriteLine($"Solveurs embarques (org.tweetyproject.math.opt.solver.*) : {string.Join(", ", solvers)}");
Console.WriteLine("Solveur general par defaut configure : " + (org.tweetyproject.math.opt.solver.Solver.hasDefaultGeneralSolver() ? "OUI" : "NON - sans lui, RpclMeReasoner.query()/getModel() termine le process"));
// --- Ancien code original, conserve pour reference historique (API inexacte, non reactivable tel quel) ---
// La DLL tweety-rpcl.dll expose 0 types `org.tweetyproject.logics.*`
// alors que le JAR shade contient toutes les classes. Bug IKVM 8.15 sur JAR shades
// avec deps transitives. Sibling PL (Tweety-2c-FOL) OK.
//
// // Construire un RpclBeliefSet avec 3 conditionnels et raisonner dessus.// using org.tweetyproject.logics.fol.syntax;// using org.tweetyproject.logics.rpcl.syntax;// using org.tweetyproject.logics.rpcl.reasoner;// using org.tweetyproject.logics.rpcl.semantics;// using org.tweetyproject.math.probability;//// // Predicats et variable.// var fever = new FolPredicate("fever");// var flu = new FolPredicate("flu");// var cold = new FolPredicate("cold");// var x = new org.tweetyproject.logics.commons.syntax.Variable("x");//// // Base de croyances RP-CL : 3 regles medicales avec probabilites.// // R1 : fever => flu [0.7] (grippe probable si fievre)// // R2 : fever => cold [0.5] (rhume aussi possible si fievre)// // R3 : flu => !cold [0.8] (grippe et rhume mutuellement exclusifs)// var bs = new RpclBeliefSet();// bs.add(new RelationalProbabilisticConditional(new FolAtom(fever, x), new FolAtom(flu, x), new Probability(0.7)));// bs.add(new RelationalProbabilisticConditional(new FolAtom(fever, x), new FolAtom(cold, x), new Probability(0.5)));// bs.add(new RelationalProbabilisticConditional(new FolAtom(flu, x), new org.tweetyproject.logics.pl.syntax.Negation(new FolAtom(cold, x)), new Probability(0.8)));// Console.WriteLine($"Base RP-CL : {bs.size()} conditionnels probabilistes.");//// // Raisonner : Maximum Entropy sur la semantique de reference (RpclProbabilityDistribution).// var me = new RpclMeReasoner();// var dist = me.getModel(bs);// Console.WriteLine($"Distribution Maximum Entropy obtenue : {dist.GetType().Name}");//Types org.tweetyproject.logics.rpcl.* charges : 31
RelationalProbabilisticConditional PRESENT
RpclBeliefSet PRESENT
RpclMeReasoner PRESENT
RpclProbabilityDistribution PRESENT
ReferenceWorld PRESENT
AggregatingSemantics PRESENT
Solveurs embarques (org.tweetyproject.math.opt.solver.*) : AntColonyOptimization, ApacheCommonsCMAESOptimizer, ApacheCommonsNonLinearConjugateGradientOptimizer, ApacheCommonsSimplex, BfgsSolver, CombinatoricsSolver, GlpkSolver, GradientDescent, GurobiOptimizer, HessianGradientDescent, IteratedLocalSearch, IteratedLocalSearchOnConstrProb, LagrangeSolver, LpSolve, OctaveSqpSolver, SimpleGeneticOptimizationSolver, SimpleGeneticOptimizationSolverCombinatorics, SimulatedAnnealing, SimulatedAnnealingOnConstrProb, Solver, StochasticLocalSearch, StochasticLocalSearchOnConstrProb, TabuSearch, TabuSearchOnConstrProb
Solveur general par defaut configure : NON - sans lui, RpclMeReasoner.query()/getModel() termine le process
Une fois la distribution Maximum Entropy calculee, on peut interroger la probabilite d’une formule FOL avec RpclMeReasoner.query(beliefset, formula). Cela retourne la somme des probabilites des mondes compatibles avec la formule, sous la distribution ME.
Cas pedagogique canonique : Etant donne les 3 règles medicales (R1, R2, R3), quelle est la probabilite que le patient ait la grippe ? - La base fixe les conditionnelles (P(flu|fever) = 0.7) mais aucune marginale : P(fever) n’est fixée nulle part. C’est précisément l’information manquante que ME fournit — la distribution la moins informative compatible avec R1-R3. - RpclMeReasoner.query(bs, formula) fait ce calcul automatiquement — la cellule ci-dessous exécute réellement cette requête (un solveur par défaut est configuré au préalable) et intercepte son refus : les trois probabilités restent non calculées tant que le verrou solveur n’est pas levé (verdict section 1).
// Requete ME : tentative REELLE (solveur par defaut configure pour eviter la terminaison du process),
// refus intercepte et affiche - aucune probabilite n'est simulee.
// Le probleme ME de RpclMeReasoner est sous CONTRAINTES : NLCG refuse (sans contraintes),
// CMAES refuse (contraintes de bord seulement), Gurobi exige une licence native absente.
var nlcg = new org.tweetyproject.math.opt.solver.ApacheCommonsNonLinearConjugateGradientOptimizer(10000, 1e-9);
org.tweetyproject.math.opt.solver.Solver.setDefaultGeneralSolver(nlcg);
var me = new org.tweetyproject.logics.rpcl.reasoner.RpclMeReasoner(new org.tweetyproject.logics.rpcl.semantics.AggregatingSemantics());
try
{
Console.WriteLine($"P(flu) = {me.query(bs, A_flu):F3}");
Console.WriteLine($"P(cold) = {me.query(bs, A_cold):F3}");
Console.WriteLine($"P(fever) = {me.query(bs, A_fever):F3}");
}
catch (Exception ex)
{
var msg = ex.InnerException?.Message ?? ex.Message;
Console.WriteLine($"Requete ME refusee par le solveur configure (exception interceptee) : {msg}");
Console.WriteLine("P(flu), P(cold), P(fever) restent non calculees ici ; aucune valeur n'est simulee.");
Console.WriteLine("Levee du verrou : solveur sous contraintes (Gurobi) ou rebuild du shade - verdict section 1.");
}
// --- Ancien code original, conserve pour reference historique (API inexacte, non reactivable tel quel) ---
// La DLL tweety-rpcl.dll expose 0 types `org.tweetyproject.logics.*`
// alors que le JAR shade contient toutes les classes. Bug IKVM 8.15 sur JAR shades
// avec deps transitives. Sibling PL (Tweety-2c-FOL) OK.
//
// // Query : probabilite de flu(x), cold(x), fever(x) sous Maximum Entropy.// using org.tweetyproject.logics.fol.syntax;// using org.tweetyproject.logics.rpcl.reasoner;// var fever = new FolPredicate("fever");// var flu = new FolPredicate("flu");// var cold = new FolPredicate("cold");// var x = new org.tweetyproject.logics.commons.syntax.Variable("x");// var me = new RpclMeReasoner();//// // On re-utilise la base de la cellule 9 (R1+R2+R3).// var bs = new RpclBeliefSet();// bs.add(new RelationalProbabilisticConditional(new FolAtom(fever, x), new FolAtom(flu, x), new org.tweetyproject.math.probability.Probability(0.7)));// bs.add(new RelationalProbabilisticConditional(new FolAtom(fever, x), new FolAtom(cold, x), new org.tweetyproject.math.probability.Probability(0.5)));// bs.add(new RelationalProbabilisticConditional(new FolAtom(flu, x), new org.tweetyproject.logics.pl.syntax.Negation(new FolAtom(cold, x)), new org.tweetyproject.math.probability.Probability(0.8)));//// // Query : probabilite de chaque predicat sous la distribution ME.// var qFlu = new FolAtom(flu, x);// var qCold = new FolAtom(cold, x);// var qFever = new FolAtom(fever, x);// Console.WriteLine($"P(flu) = {me.query(bs, qFlu):F3}");// Console.WriteLine($"P(cold) = {me.query(bs, qCold):F3}");// Console.WriteLine($"P(fever) = {me.query(bs, qFever):F3}");//Requete ME refusee par le solveur configure (exception interceptee) : Only optimization problems without constraints allowed for this solver.
P(flu), P(cold), P(fever) restent non calculees ici ; aucune valeur n'est simulee.
Levee du verrou : solveur sous contraintes (Gurobi) ou rebuild du shade - verdict section 1.
Stubs sans
throw/raise(convention C.1) : le notebook s’execute de bout en bout même non complete.
Construisez un système RP-CL medical avec : - fever => flu [0.6] - flu => cough [0.8] - cough => sore_throat [0.5]
Verifiez avec RpclMeReasoner.query(...) que P(cough) est inferiee par chainage. (Intuition : P(cough) = P(fever) * P(flu|fever) * P(cough|flu).)
Indice : RpclBeliefSet + 3 RelationalProbabilisticConditional + me.query(bs, queryFormula).
Construisez une base avec deux conditionnels contradictoires : - wet => rain [0.9] - wet => !rain [0.8]
Que retourne RpclMeReasoner.query(bs, rain) ? La distribution ME resout-elle le conflit ? (Indice : ME cherche la distribution compatible la moins informative ; rien ne garantit qu’elle existe ici - deux contraintes incompatibles sur la meme premisse peuvent rendre la base insatisfiable.)
Indice 2 : question d’investigation - documentez ce que vous observez (refus, distribution inexistante, probabilite intermediaire ?) plutot que de supposer un moyennage garanti ; confrontez le resultat a la theorie de Paris / Kern-Isberner sur les bases incoherentes.
P(rain) avec conditionnels contradictoires sous ME = Exercice a completer
Modelisez un système expert financier avec 4 règles RP-CL : - bull_market => stock_up [0.8] - bear_market => stock_down [0.85] - stock_up => dividend_high [0.7] - stock_down => dividend_low [0.9]
Utilisez RpclMeReasoner pour calculer P(dividend_high) et P(dividend_low) (en esperant qu’elles somment a 1 si le système est coherent).
Indice : 6 predicats (bull_market, bear_market, stock_up, stock_down, dividend_high, dividend_low) + 4 RelationalProbabilisticConditional + 2 queries.
P(dividend_high), P(dividend_low) sous systeme expert = Exercice a completer
On a porte en C#/.NET natif (sans JVM) le module logics-rpcl de TweetyProject - la Ranking Probabilistic Conditional Logic - via IKVM, ouverture sur les logiques probabilistes :
RP-CL est le chainon manquant entre logique conditionnelle et raisonnement probabiliste : la combinaison des deux permet d’encoder des systèmes experts stochastiques avec des règles defeasibles ponderees. Le raisonneur par Maximum Entropy (RpclMeReasoner) est la méthode de reference pour calculer la distribution la moins informative compatible avec les contraintes (principe de Jaynes - développé en section 3).
6300d915 : IKVM 8.14 + shade en bytecode Java 8), la DLL expose bien les types RPCL - l’ancien diagnostic « 0 type expose / bug IKVM 8.15 » etait perime (re-mesure : 31 types logics.rpcl.*, section 3 du notebook).FolAtom, Negation, conditionnels probabilistes, complement()).RpclMeReasoner est sous contraintes ; aucun des solveurs generaux embarques ne le couvre (NLCG : sans contraintes ; CMAES : contraintes de bord seulement ; Gurobi : licence native absente). La section 4 execute la tentative et intercepte le refus reel du solveur. Pistes de levee NON VERIFIEES : solveur sous contraintes (Gurobi, si licence/native disponibles) ou recompilation du shade (dotnet-build/build-TweetyRpclShade.csproj) - aucune n’a ete demontree.commons.syntax.Predicate au lieu de FolPredicate, variables a majuscule, Probability(java.lang.Double)).