Red Hat Decision Manager PMMLファイルの実行

Red Hat Decision Managerでは、PMML形式のファイルをそのまま読み込んで、ルールとして実行可能になっています。ここでは、PMMLファイルを読み込んで実行する方法について紹介します。

注）記事内容はすべて個人の見解に基づくものであり、RedHat社の公式見解ではありません。


## PMMLとは

**Predictive Model Markup Language(PMML)**

データ分析モデリング用のマークアップ言語。XMLベース。
[DataMiningGroup](http://dmg.org/)にて策定。
データマイニングツールや機械学習ツールなどで、出力形式の一つとしてPMMLがある。

データ分析・機械学習のアウトプットは、何かと言えば、いわゆるルールなわけで。
「これこれこういう条件のデータの場合、こういう結果が導き出されますよ」という統計結果。
これをもとに、一からルールを作成しても良いわけですが、そのままルールにできたら便利ですよね、ということで、PMML形式からそのまま読み込む機能がついたのだと思われます。

とはいえ、PMMLってどれほど普及しているのでしょうかね。。。？
検索してみても情報は少ないし、今後の行方はちょっとわかりません。

## サポートされるPMMLの形式

PMMLには様々なモデルがあるが、Red Hat Decision Manager(7.1.x)でサポート対象となっているのは、以下の３つのみ。

- Regression model
- Scorecard model
- Tree model

ちなみに、RHDM7.1.x系では、PMMLのバージョンは4.2.1をサポートしています。
各モデルの詳細について知りたければ、[ここ](http://dmg.org/pmml/v4-2-1/GeneralStructure.html)とか見てください。

## PMMLファイルを読み込んで実行する手順

### スコアカードの例

ここでは、製品マニュアルにあるスコアカードのサンプルPMMLを使ってみます。
（一部勝手に書き直した箇所あり）

```xml
<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.dmg.org/PMML-4_2">
  <Header copyright="JBoss"/>
  <DataDictionary numberOfFields="3">
    <DataField name="param1" optype="continuous" dataType="double"/>
    <DataField name="param2" optype="continuous" dataType="double"/>
    <DataField name="finalscore" optype="continuous" dataType="double" />
  </DataDictionary>
  <Scorecard modelName="ScorecardCompoundPredicate" useReasonCodes="true" isScorable="true" functionName="regression"    baselineScore="15" initialScore="0.8" reasonCodeAlgorithm="pointsAbove">
    <MiningSchema>
      <MiningField name="param1" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="param2" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="finalscore" usageType="target"/>
    </MiningSchema>
    <Characteristics>
      <Characteristic name="ch1" baselineScore="50" reasonCode="reasonCh1">
        <Attribute partialScore="20">
          <SimplePredicate field="param1" operator="lessThan" value="20"/>
        </Attribute>
        <Attribute partialScore="100">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param1" operator="greaterOrEqual" value="20"/>
            <SimplePredicate field="param2" operator="lessOrEqual" value="25"/>
          </CompoundPredicate>
        </Attribute>
        <Attribute partialScore="200">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param1" operator="greaterOrEqual" value="20"/>
            <SimplePredicate field="param2" operator="greaterThan" value="25"/>
          </CompoundPredicate>
        </Attribute>
      </Characteristic>
      <Characteristic name="ch2" reasonCode="reasonCh2">
        <Attribute partialScore="10">
          <CompoundPredicate booleanOperator="or">
            <SimplePredicate field="param2" operator="lessOrEqual" value="-5"/>
            <SimplePredicate field="param2" operator="greaterOrEqual" value="50"/>
          </CompoundPredicate>
        </Attribute>
        <Attribute partialScore="20">
          <CompoundPredicate booleanOperator="and">
            <SimplePredicate field="param2" operator="greaterThan" value="-5"/>
            <SimplePredicate field="param2" operator="lessThan" value="50"/>
          </CompoundPredicate>
        </Attribute>
      </Characteristic>
    </Characteristics>
  </Scorecard>
</PMML>
```

ここでは、スコアカードの詳細説明は省略しますが、ざっと解説しますと、

```xml
  <DataDictionary numberOfFields="3">
    <DataField name="param1" optype="continuous" dataType="double"/>
    <DataField name="param2" optype="continuous" dataType="double"/>
    <DataField name="finalscore" optype="continuous" dataType="double" />
  </DataDictionary>
```

double型のデータが、３つ定義されています。
`optype="continuous"`とあるので、算術演算子で条件をつけられるフィールドということになります。

```xml
<Scorecard modelName="ScorecardCompoundPredicate" useReasonCodes="true" isScorable="true" functionName="regression"    baselineScore="15" initialScore="0.8" reasonCodeAlgorithm="pointsAbove">
・・・
</Scorecard>
```
ここが、スコアカードのモデル定義です。
モデル名は、`"ScorecardCompoundPredicate"`とのこと。
baselineScoreが"15"、initialScoreが"0.8"に設定されています。

```xml
    <MiningSchema>
      <MiningField name="param1" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="param2" usageType="active" invalidValueTreatment="asMissing">
      </MiningField>
      <MiningField name="finalscore" usageType="target"/>
    </MiningSchema>
```
`usageType="active"`とあるのが、インプットフィールドです。ここでは、param1とparam2がインプットになっています。

`<Characteristics>・・・</Characteristics>`内に、スコアカードの結果が定義されています。
ここでは、`ch1`と`ch2`の2つのCharacteristicがありますね。それぞれ表にしてみると、こんな感じです。

**ch1** 
baselineScoreは50

| param1  | param2  |    PartialScore | 
|:--------|:--------|----------------:|
| < 20    |         |              20 |
| >=20    |< 25     |             100 |
| >=20    |>= 25    |             200 |

**ch2**

| param2         |  PartialScore | 
|:---------------|--------------:|
| <=-5           |            10 |
| > 50           |            10 |
| > -5 and < 50  |            20 |

###pom.xml

PMMLファイルを読み込んで実行するには、以下のdependencyが必要です。

```xml
// Required for the PMML compiler
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>kie-pmml</artifactId>
  <version>${rhdm.version}</version>
</dependency>

// Required for the KIE public API
<dependency>
  <groupId>org.kie</groupId>
  <artifactId>kie-api</artifactId>
  <version>${rhdm.version}</version>
</dependency>

// Required if not using classpath KIE container
<dependency>
  <groupId>org.kie</groupId>
  <artifactId>kie-ci</artifactId>
  <version>${rhdm.version}</version>
</dependency>
```

###PMMLファイルの読み込み

PMMLファイルを用意したら、ファイルパスを指定して以下のようにKieBaseを作ります。

```java
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.io.ResourceType;

・・・

KieServices ks = KieServices.Factory.get();

// PMMLPATHにPMMLファイルパスを指定。
KieFileSystem kfs = ks.newKieFileSystem();
kfs.write( ks.getResources().newFileSystemResource( PMMLPATH )
				   .setResourceType( ResourceType.PMML ) );

KieBuilder kieBuilder = ks.newKieBuilder( kfs );
// ここでビルド（PMMLファイルからのビルドは少し時間かかる）
kieBuilder.buildAll();

KieContainer kieContainer = ks.newKieContainer( kieBuilder.getKieModule().getReleaseId() );
KieBase kbase = kieContainer.getKieBase();
```

###PMMLファイルの実行クラス

PMMLの実行には、`RuleUnitExecutor`を使います。
RuleUnitExecutorには、データソースとして、"request"、"results"、"pmmlData"の3つを新規追加する必要があります。

```java
RuleUnitExecutor executor = RuleUnitExecutor.create().bind(kbase);
DataSource<PMMLRequestData> requestData = executor.newDataSource("request");
DataSource<PMML4Result> resultData = executor.newDataSource("results");
DataSource<PMML4Data> internalData = executor.newDataSource("pmmlData");
```

###インサートするファクトクラス

PMML実行用にあらかじめファクトクラスが準備されています。

- PMMLRequestData
    - このファクトの`requestParams`にインプットデータをセットして渡す
- PMML4Result
    - 結果がセットされるファクト


####PMML実行サンプルコード

以下がPMMLファイルの実行コードのサンプルです。

```java
package com.sample;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.drools.core.definitions.InternalKnowledgePackage;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.ruleunit.RuleUnitDescription;
import org.drools.core.ruleunit.RuleUnitDescriptionRegistry;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.io.ResourceType;
import org.kie.api.pmml.PMML4Data;
import org.kie.api.pmml.PMML4Result;
import org.kie.api.pmml.PMMLRequestData;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.rule.DataSource;
import org.kie.api.runtime.rule.RuleUnit;
import org.kie.api.runtime.rule.RuleUnitExecutor;
import org.kie.pmml.pmml_4_2.model.PMML4UnitImpl;

public class PmmlTest {

    public static String PMMLPATH = "/path";

    public static final void main(String[] args) {
        try {
            
            KieServices ks = KieServices.Factory.get();

            KieFileSystem kfs = ks.newKieFileSystem();
            kfs.write( ks.getResources().newFileSystemResource( PMMLPATH )
                               .setResourceType( ResourceType.PMML ) );
            
            KieBuilder kieBuilder = ks.newKieBuilder( kfs );
            kieBuilder.buildAll();

            KieContainer kieContainer = ks.newKieContainer( kieBuilder.getKieModule().getReleaseId() );
            KieBase kbase = kieContainer.getKieBase();
                        
            RuleUnitExecutor executor = RuleUnitExecutor.create().bind(kbase);
            DataSource<PMMLRequestData> requestData = executor.newDataSource("request");
            DataSource<PMML4Result> resultData = executor.newDataSource("results");
            DataSource<PMML4Data> internalData = executor.newDataSource("pmmlData");

            String correlationId = "id";
            String modelName = "ScorecardCompoundPredicate";
            String modelPkgName = "org.drools.scorecards.example";
            
            // インプットデータの生成
            Map<String, Object> variables = new HashMap<String, Object>();
            variables.put("param1", 20d);
            variables.put("param2", 10d);
            
            PMMLRequestData request = new PMMLRequestData(correlationId, modelName);
            variables.entrySet().forEach( es -> {
                request.addRequestParam(es.getKey(), es.getValue());
            });
            PMML4Result resultHolder = new PMML4Result(correlationId);

            requestData.insert(request);
            resultData.insert(resultHolder);
            
            List<String> possiblePackageNames = calculatePossiblePackageNames(modelName, modelPkgName);
            // "RuleUnitIndicator"は固定値
            Class<? extends RuleUnit> ruleUnitClass = getStartingRuleUnit("RuleUnitIndicator",
                (InternalKnowledgeBase)kbase,
                possiblePackageNames);

			if (ruleUnitClass != null) {
                // ここで実行
				executor.run(ruleUnitClass);
				System.out.println("===>result");
				if ( "OK".equals(resultHolder.getResultCode()) ) {
					// 結果をコンソール出力
					System.out.println(resultHolder.getResultVariables().toString());
				}
			}            
                        

        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    protected static Class<? extends RuleUnit> getStartingRuleUnit(String startingRule, InternalKnowledgeBase ikb, List<String> possiblePackages) {
        RuleUnitDescriptionRegistry unitRegistry = ikb.getRuleUnitDescriptionRegistry();
        Map<String,InternalKnowledgePackage> pkgs = ikb.getPackagesMap();
        RuleImpl ruleImpl = null;
        for (String pkgName: possiblePackages) {
          if (pkgs.containsKey(pkgName)) {
              InternalKnowledgePackage pkg = pkgs.get(pkgName);
              ruleImpl = pkg.getRule(startingRule);
              if (ruleImpl != null) {
                  RuleUnitDescription descr = unitRegistry.getDescription(ruleImpl).orElse(null);
                  if (descr != null) {
                      return descr.getRuleUnitClass();
                  }
              }
          }
        }
        return null;
    }
    
    protected static List<String> calculatePossiblePackageNames(String modelId, String...knownPackageNames) {
        List<String> packageNames = new ArrayList<>();
        String javaModelId = modelId.replaceAll("\\s","");
        if (knownPackageNames != null && knownPackageNames.length > 0) {
            for (String knownPkgName: knownPackageNames) {
                packageNames.add(knownPkgName + "." + javaModelId);
            }
        }
        String basePkgName = PMML4UnitImpl.DEFAULT_ROOT_PACKAGE+"."+javaModelId;
        packageNames.add(basePkgName);
        return packageNames;
    }
}
```

###実行結果の確認

上記のサンプルコードを実行して、出力結果を見てみます。
上記を実行すると、ビルドに時間がかかりますが、実行自体は瞬時に終わります。
以下は、実行時のログ例です。

```text
Starting - org.kie.pmml.pmml_4_2.ScorecardCompoundPredicate.ScorecardCompoundPredicateScorecardRuleUnit
Rules execution available for ScorecardCompoundPredicateScorecardRuleUnit
Ending - org.kie.pmml.pmml_4_2.ScorecardCompoundPredicate.ScorecardCompoundPredicateScorecardRuleUnit
===>result
{ScoreCard=ScoreCard [modelName=ScorecardCompoundPredicate, score=120.8, holder=ScorecardCompoundPredicateScoreCardDataScoreCardData( correlationId=id, modelName=ScorecardCompoundPredicate,  mFinalscore=true,  vFinalscore=null,  mParam1=false,  vParam1=20.0,  mParam2=false,  vParam2=10.0 ), enableRC=true, pointsBelow=false, ranking={reasonCh1=50.0, reasonCh2=5.0}], Finalscore=Finalscore( value=120.8, context=ScorecardCompoundPredicate, valid=true, missing=false, name=null, displayValue=Finalscore, weight=1.0 )}
```

ScoreCardというファクトがあらかじめ定義されています。

```java
public class ScoreCard {
    private String modelName;
    private double score;
    private AbstractPMMLData holder;
    private boolean enableRC;
    private boolean pointsBelow;
    private Map ranking;
・・・
```

このscoreが、最終的なスコアになります。
ここでは、120.8になっています。
ch1のPartialScoreが100。
ch2のPartialScoreが20。

100 + 20 + 0.8(initialScore) = 120.8

ちなみに、reasonCodeごとでは、
ch1は、baselineScore=50、reasonCodeAlgorithmがpointsAboveなので、ch1は、50。
ch2は、baselineScoreは全体の設定値の15が採用されるので、ch2は、5。

ということになります。

###PMMLのDRL変換について

PMMLファイルは内部でDRLに変換されて、実行されています。
どのようなDRLが生成されているのか、を確認したい場合は、PMML4Compilerを使います。

```java
    public static void DTtoDRL(String pmmlpath){
    	
    	try (InputStream is = new FileInputStream(pmmlpath)){
    		PMML4Compiler compiler = new PMML4Compiler();
	        String drl=compiler.compile(is, Class.class.getClassLoader());
	        // DRLにコンパイルした結果をコンソール出力
	        System.out.println(drl);
        
    	} catch (Exception e){
    		e.printStackTrace();
    	}
    }
```

###DRL変換例

こんな感じに、DRLが生成されています。かなーり長いです。

```
// Imported PMML Model Theory
// Trained with : 
// Creation timestamp : 
// Description : 
// Copyright : JBoss




package org.kie.pmml.pmml_4_2.test;
unit ScorecardCompoundPredicateScorecardRuleUnit

import org.kie.pmml.pmml_4_2.*;
import org.kie.pmml.pmml_4_2.model.*;
import org.kie.pmml.pmml_4_2.model.scorecard.*;
import org.kie.pmml.pmml_4_2.model.regression.*;
import org.kie.pmml.pmml_4_2.model.tree.*;
import org.kie.pmml.pmml_4_2.model.datatypes.*;
import org.drools.core.factmodel.traits.Traitable;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.pmml.PMMLRequestData;
import org.kie.api.pmml.ParameterInfo;
import org.kie.api.pmml.PMML4Result;
import org.kie.api.pmml.PMML4Data;
import org.kie.api.pmml.PMML4DataType;


rule 'RuleUnitIndicator'
when
then
   System.out.println("Rules execution available for ScorecardCompoundPredicateScorecardRuleUnit");
end

rule 'Extract Parameter Info'
@Generated
salience 10
no-loop
when
   $rd: PMMLRequestData( $cid: correlationId != null, $mn: modelName ) from request
   $pi: ParameterInfo( $name: name, $value: value ) from $rd.mappedRequestParams.values()
then
   PMML4DataFactory factory = PMML4DataFactory.get();
   PMML4Data data = factory.newPMML4Data($cid, $mn, $pi, false, false);
   pmmlData.insert(data);
end

rule "Override Value"
 

  @Generated   
salience 2
when
   $new: PMML4Data( $value: value ) from pmmlData
   $old: PMML4Data( this != $new, name == $new.name, value != $value, this before[0] $new ) from pmmlData
then
   retract($old);
end











declare PMML4AbstractField
end

declare DataField extends PMML4AbstractField
 @role(event)
   valid : boolean   = false      @position(2)
   missing : boolean  = false     @position(3) @key
   context : String @key          @position(1)
   name    : String
//   cyclic = (false) : boolean
//   continuous = (false) : boolean
//   categorical = (false) : boolean
//   ordinal = (false) : boolean
end

declare OutputField extends DataField
@role(event)

    warning  : String = "No Warning"
    target   : boolean  = false

end



















 // Display Name : null
 
 declare Finalscore extends  DataField 
  @role(event)
  @Traitable

    value : double @key @position(0) 
    displayValue : String =  "Finalscore" 

    weight : double = 1.0   @key

    
 end


















rule "Valid_PMML4DataUnrestricted_Values_Finalscore-null"
 

  @Generated   
dialect 'java'
no-loop
salience 9999
when
   $in : PMML4Data( capitalizedName == "Finalscore", valid == false, placeholder == false  ) from pmmlData
then
   modify($in) {
      setValid( true );
   }
end


















 // Display Name : null
 
 declare Param2 extends  DataField 
  @role(event)
  @Traitable

    value : double @key @position(0) 
    displayValue : String =  "Param2" 

    weight : double = 1.0   @key

    
 end


















rule "Valid_PMML4DataUnrestricted_Values_Param2-null"
 

  @Generated   
dialect 'java'
no-loop
salience 9999
when
   $in : PMML4Data( capitalizedName == "Param2", valid == false, placeholder == false  ) from pmmlData
then
   modify($in) {
      setValid( true );
   }
end


















 // Display Name : null
 
 declare Param1 extends  DataField 
  @role(event)
  @Traitable

    value : double @key @position(0) 
    displayValue : String =  "Param1" 

    weight : double = 1.0   @key

    
 end


















rule "Valid_PMML4DataUnrestricted_Values_Param1-null"
 

  @Generated   
dialect 'java'
no-loop
salience 9999
when
   $in : PMML4Data( capitalizedName == "Param1", valid == false, placeholder == false  ) from pmmlData
then
   modify($in) {
      setValid( true );
   }
end





















rule "Mark_ScorecardCompoundPredicate"
salience 10000
no-loop
when
//    not ModelMarker( "ScorecardCompoundPredicate" ; )
then
//    System.out.println( "Marking ScorecardCompoundPredicate" );
    ModelMarker mark = new ModelMarker( "ScorecardCompoundPredicate", "Scorecard" );
    insert( mark );
end

rule "Enable/Disable Model_ScorecardCompoundPredicate"
salience 10000
when
    $flag : Boolean() from entry-point "enable_ScorecardCompoundPredicate"
    $mark : ModelMarker( modelName == "ScorecardCompoundPredicate", enabled != $flag )
then
    delete( $flag );
    modify ( $mark ) {
        setEnabled( $flag );
    }
end

rule "Cleanup data_ScorecardCompoundPredicate"
salience -10000
when
    $mark : ModelMarker( modelName == "ScorecardCompoundPredicate", enabled == false )
    $data : DataField( context == "ScorecardCompoundPredicate" )
then
    delete( $data );
end












rule "Score Card ScorecardCompoundPredicate"
 

  @Generated   
salience -10  // after data are stable
when
    $card : ScoreCard( $ctx : modelName )
    InitialScore( scoreCard == $ctx, $zero : value )
    accumulate(
        PartialScore( scoreCard == $ctx, $val : value, $wgt : weight ),
        $tot : sum( $val  );
        ((Double)$tot) + $zero != $card.getScore() )
then
    modify ( $card ) {
        setScore( $zero + ((Double)$tot) );
    }
end


rule "Cumulate Code Scores"
 

  @Generated   
salience -11
when
    $card : ScoreCard( $ctx : modelName, enableRC == true, $below : pointsBelow )
    accumulate( PartialScore( scoreCard == $ctx, $rc : reasonCode != null ),
                $set : collectSet( $rc ) )
    $code : String() from $set
    accumulate( PartialScore( scoreCard == $ctx, reasonCode == $code, $val : value, $char : characteristic )
                and
                BaselineScore( scoreCard == $ctx, characteristic == $char, $base : value ),
                // FIXME: DROOLS-1248
                $sum : sumBD( java.math.BigDecimal.valueOf( $below ? ($base - $val) : ($val - $base) ) ) )
then
//    System.out.println( "The CUMULATED score for code " + $code + " from set " + $set + " is >>> " + $sum );
    insertLogical( new CodeScore( $card, $code, $sum.doubleValue() ) );
end


rule "Detect Scorecard ReasonCode Change"
 

  @Generated   
salience -12
when
    $sc :  ScoreCard( enableRC == true, $map : ranking )
    exists CodeScore( $c : code, score != $map.get( $c ) )
then
    insert( new ScoreRank( $sc, new java.util.LinkedHashMap() ) );
end


rule "Sort Scorecard Reason Codes"
 

  @Generated   
salience -14
when
    $r  : ScoreRank( $sc : scoreCard, $map : rank )
    $cs : CodeScore( scoreCard == $sc, ! $map.containsKey( code ), $s : score, $c : code )
    not   CodeScore( scoreCard == $sc, ! $map.containsKey( code ), score > $s )
then
    modify ( $r ) {
        getRank().put( $c, $s );
    }
end


rule "Integrate Scorecard ReasonCode Map"
 

  @Generated   
salience -15
when
    $s : ScoreCard( enableRC == true )
    $x : ScoreRank( scoreCard == $s, $map : rank )
   $reslt: PMML4Result( resultVariables == null || "ScoreCard" not memberOf resultVariables.keySet() ) from results
then
    retract( $x );
    modify ( $s ) {
        setRanking( $map );
    }
   $reslt.setResultCode("OK");
   $reslt.addResultVariable("ScoreCard",$s);
   update($reslt);
end
/*
rule "Add Scorecard to PMMLResult"
 

  @Generated   
salience -16
when
   $sc: ScoreCard( )
   $reslt: PMML4Result( resultVariables == null || "ScoreCard" not memberOf resultVariables.keySet() ) from results
then
   System.out.println("Adding Scorecard to PMMLResult");
   $reslt.setResultCode("OK");
   $reslt.addResultVariable("ScoreCard",$sc);
   update($reslt);
end
*/
rule "Update Scorecard in PMMLResult"
salience -16
no-loop
when
   $reslt: PMML4Result( "Scorecard" memberOf resultVariables.keySet() ) from results
   $scold: ScoreCard() from $reslt.resultVariables["ScoreCard"]
   $sc: ScoreCard()
then
   $reslt.updateResultVariable("ScoreCard",$sc);
   update($reslt);
end






 








rule miningPmml4Data_ScorecardCompoundPredicate_Param2
 

  @Generated   
when
   $src: PMML4Data( name == "param2", $m : missing, $v : valid, $x : value, context == null, placeholder == false ) from pmmlData
then
   PMML4Data data = (PMML4Data)PMML4DataFactory.get().copy($src);
   data.setContext("ScorecardCompoundPredicate");
   pmmlData.insert(data);
end;


rule "InitAsMissing_PMML4Data_ScorecardCompoundPredicate_Param2"
 

  @Generated   
salience 1000
when
   ModelMarker( modelName == "ScorecardCompoundPredicate", enabled == true )
   not PMML4Data( capitalizedName == "Param2", context == null ) from pmmlData
then
   PMML4DataType data = PMML4DataFactory.get().getPlaceholder("","Param2","ScorecardCompoundPredicate");
   pmmlData.insert( data );
end



rule "RemoveMissing_PMML4Data_ScorecardCompoundPredicate_Param2"
 

  @Generated   
salience 1000
when
    $val : PMML4Data( capitalizedName == "Param2", context == "ScorecardCompoundPredicate", missing == false ) from pmmlData
    $mis : PMML4Data( capitalizedName == "Param2", context == "ScorecardCompoundPredicate", missing == true ) from pmmlData
then
    delete( $mis );
end




 







rule "miningFieldInvalid_PMML4Data_ScorecardCompoundPredicate_Param2"
 

  @Generated   
salience 999
when
   $x: PMML4Data( capitalizedName == "Param2", $m : missing, $v : valid == false, placeholder == false,
                  context == "ScorecardCompoundPredicate" ) from pmmlData
then
   delete( $x );
   $x.setValue( 0.0 );
   $x.setMissing( true );
   $x.setValid( true );
   pmmlData.insert( $x );
end


rule "miningFieldInvalid_ScorecardCompoundPredicate_Param2"
 

  @Generated   
salience 999
when
 $x : Param2( $m : missing, $v : valid == false,
               context == "ScorecardCompoundPredicate" )
then
    delete( $x );
        //null
        $x.setValue( 0.0 );
        $x.setMissing( true );
        $x.setValid( true );
    insert( $x );
end



 








rule miningPmml4Data_ScorecardCompoundPredicate_Param1
 

  @Generated   
when
   $src: PMML4Data( name == "param1", $m : missing, $v : valid, $x : value, context == null, placeholder == false ) from pmmlData
then
   PMML4Data data = (PMML4Data)PMML4DataFactory.get().copy($src);
   data.setContext("ScorecardCompoundPredicate");
   pmmlData.insert(data);
end;


rule "InitAsMissing_PMML4Data_ScorecardCompoundPredicate_Param1"
 

  @Generated   
salience 1000
when
   ModelMarker( modelName == "ScorecardCompoundPredicate", enabled == true )
   not PMML4Data( capitalizedName == "Param1", context == null ) from pmmlData
then
   PMML4DataType data = PMML4DataFactory.get().getPlaceholder("","Param1","ScorecardCompoundPredicate");
   pmmlData.insert( data );
end



rule "RemoveMissing_PMML4Data_ScorecardCompoundPredicate_Param1"
 

  @Generated   
salience 1000
when
    $val : PMML4Data( capitalizedName == "Param1", context == "ScorecardCompoundPredicate", missing == false ) from pmmlData
    $mis : PMML4Data( capitalizedName == "Param1", context == "ScorecardCompoundPredicate", missing == true ) from pmmlData
then
    delete( $mis );
end




 







rule "miningFieldInvalid_PMML4Data_ScorecardCompoundPredicate_Param1"
 

  @Generated   
salience 999
when
   $x: PMML4Data( capitalizedName == "Param1", $m : missing, $v : valid == false, placeholder == false,
                  context == "ScorecardCompoundPredicate" ) from pmmlData
then
   delete( $x );
   $x.setValue( 0.0 );
   $x.setMissing( true );
   $x.setValid( true );
   pmmlData.insert( $x );
end


rule "miningFieldInvalid_ScorecardCompoundPredicate_Param1"
 

  @Generated   
salience 999
when
 $x : Param1( $m : missing, $v : valid == false,
               context == "ScorecardCompoundPredicate" )
then
    delete( $x );
        //null
        $x.setValue( 0.0 );
        $x.setMissing( true );
        $x.setValid( true );
    insert( $x );
end













rule "Scorecard ScorecardCompoundPredicate output - Finalscore"
 

  @Generated   
salience -5
when
    ScoreCard( modelName == "ScorecardCompoundPredicate", $score : score )
then
    Finalscore x = new Finalscore();
        x.setContext( "ScorecardCompoundPredicate" );
        x.setValid( true );
        x.setMissing( false );
        x.setValue( $score );
    insertLogical( x );
end

rule "Add PMMLResult with Scorecard output ScorecardCompoundPredicate - Finalscore"
 

  @Generated   
dialect "java"
when
   $tgt: Finalscore()
   $reslt: PMML4Result( resultVariables == null || "Finalscore" not memberOf resultVariables.keySet() ) from results
then
   $reslt.setResultCode("OK");
   $reslt.addResultVariable("Finalscore",$tgt);
   update($reslt);
end


rule "Update PMMLResult containing Scorecard output ScorecardCompoundPredicate - Finalscore"
 

  @Generated   
no-loop
when
   $reslt: PMML4Result( "Finalscore" memberOf resultVariables.keySet() ) from results
   $told: Finalscore( $v: value ) from $reslt.resultVariables["Finalscore"]
   $tgt: Finalscore( value != null && value != $v )
then
   $reslt.updateResultVariable("Finalscore",$tgt);
   update($reslt);
end



















rule "Bind_Scorecard_PMML4Data_ScorecardCompoundPredicate_Param2"
 

  @Generated   
when
   $in : PMML4Data( capitalizedName == "Param2", context == "ScorecardCompoundPredicate", 
                    placeholder == false, missing == true || valid == true, $m : missing, $v : value ) from pmmlData
   $sc : ScorecardCompoundPredicateScoreCardData( ( mParam2 == true && != $m )
                               || vParam2 != $v )
then
   modify( $sc ) {
      setMParam2( $m ),
      setVParam2( (Double)$v);
   }
end

rule "Bind_Scorecard_ScorecardCompoundPredicate_Param2"
 

  @Generated   
when
    $in : Param2( context == "ScorecardCompoundPredicate", missing == true || valid == true, $m : missing, $v : value )
    $sc : ScorecardCompoundPredicateScoreCardData( ( mParam2 == true && != $m )
                                || vParam2 != $v )
then
    modify ( $sc ) {
        setMParam2( $m ),
        setVParam2( $v );
    }
end


rule "Bind_Scorecard_PMML4Data_ScorecardCompoundPredicate_Param1"
 

  @Generated   
when
   $in : PMML4Data( capitalizedName == "Param1", context == "ScorecardCompoundPredicate", 
                    placeholder == false, missing == true || valid == true, $m : missing, $v : value ) from pmmlData
   $sc : ScorecardCompoundPredicateScoreCardData( ( mParam1 == true && != $m )
                               || vParam1 != $v )
then
   modify( $sc ) {
      setMParam1( $m ),
      setVParam1( (Double)$v);
   }
end

rule "Bind_Scorecard_ScorecardCompoundPredicate_Param1"
 

  @Generated   
when
    $in : Param1( context == "ScorecardCompoundPredicate", missing == true || valid == true, $m : missing, $v : value )
    $sc : ScorecardCompoundPredicateScoreCardData( ( mParam1 == true && != $m )
                                || vParam1 != $v )
then
    modify ( $sc ) {
        setMParam1( $m ),
        setVParam1( $v );
    }
end





















rule "Init ScoreCard ScorecardCompoundPredicate"
 

  @Generated   
when
//    ModelMarker( "ScorecardCompoundPredicate" ; enabled == true )
    $rqst: PMMLRequestData( correlationId != null, requestParams != null ) from request
then
    AbstractPMMLData data = new ScorecardCompoundPredicateScoreCardData($rqst);
//    org.kie.pmml.pmml_4_2.ScoreCardData data = new ScorecardCompoundPredicateScoreCardData ( "ScorecardCompoundPredicate" );
    ScoreCard card = new ScoreCard( "ScorecardCompoundPredicate", 0.0, data, true, false, new java.util.LinkedHashMap() );
    insert( data );
    insert( card );

     insertLogical( new InitialScore( "ScorecardCompoundPredicate", 0.8 ) ); 
end

rule "Scoring Complete"
 

  @Generated   
salience -200
when
   $tgt: ScoreCard()
   $reslt: PMML4Result( resultVariables == null || "ScoreCard" not memberOf resultVariables.keySet() ) from results
then
   $reslt.setResultCode("OK");
   $reslt.addResultVariable("ScoreCard",$tgt);
   update($reslt);
end















rule "PartialScore_ScorecardCompoundPredicate_ch1_0"
 

  @Generated   
when
    ScoreRow( scoreCard == "ScorecardCompoundPredicate", id == "ch10", $val : value, $char : characteristic, $code : reasonCode )
    $sc : ScorecardCompoundPredicateScoreCardData( ( mParam1 == false && vParam1 < 20 ) )
then
//    System.out.println( "PARTIALLY SCORING SC " + $val + " " + $char );
// weigth is null
    insertLogical( new PartialScore( "ScorecardCompoundPredicate", $val, $char, $code,  1.0  ) );
end














rule "PartialScore_ScorecardCompoundPredicate_ch2_1"
 

  @Generated   
when
    ScoreRow( scoreCard == "ScorecardCompoundPredicate", id == "ch21", $val : value, $char : characteristic, $code : reasonCode )
    $sc : ScorecardCompoundPredicateScoreCardData( ( ( mParam2 == false && vParam2 < 50 ) ) && ( ( mParam2 == false && vParam2 > -5 ) ) )
then
//    System.out.println( "PARTIALLY SCORING SC " + $val + " " + $char );
// weigth is null
    insertLogical( new PartialScore( "ScorecardCompoundPredicate", $val, $char, $code,  1.0  ) );
end














rule "PartialScore_ScorecardCompoundPredicate_ch2_2"
 

  @Generated   
when
    ScoreRow( scoreCard == "ScorecardCompoundPredicate", id == "ch20", $val : value, $char : characteristic, $code : reasonCode )
    $sc : ScorecardCompoundPredicateScoreCardData( ( ( mParam2 == false && vParam2 >= 50 ) ) || ( ( mParam2 == false && vParam2 <= -5 ) ) )
then
//    System.out.println( "PARTIALLY SCORING SC " + $val + " " + $char );
// weigth is null
    insertLogical( new PartialScore( "ScorecardCompoundPredicate", $val, $char, $code,  1.0  ) );
end














rule "PartialScore_ScorecardCompoundPredicate_ch1_3"
 

  @Generated   
when
    ScoreRow( scoreCard == "ScorecardCompoundPredicate", id == "ch12", $val : value, $char : characteristic, $code : reasonCode )
    $sc : ScorecardCompoundPredicateScoreCardData( ( ( mParam1 == false && vParam1 >= 20 ) ) && ( ( mParam2 == false && vParam2 > 25 ) ) )
then
//    System.out.println( "PARTIALLY SCORING SC " + $val + " " + $char );
// weigth is null
    insertLogical( new PartialScore( "ScorecardCompoundPredicate", $val, $char, $code,  1.0  ) );
end














rule "PartialScore_ScorecardCompoundPredicate_ch1_4"
 

  @Generated   
when
    ScoreRow( scoreCard == "ScorecardCompoundPredicate", id == "ch11", $val : value, $char : characteristic, $code : reasonCode )
    $sc : ScorecardCompoundPredicateScoreCardData( ( ( mParam1 == false && vParam1 >= 20 ) ) && ( ( mParam2 == false && vParam2 <= 25 ) ) )
then
//    System.out.println( "PARTIALLY SCORING SC " + $val + " " + $char );
// weigth is null
    insertLogical( new PartialScore( "ScorecardCompoundPredicate", $val, $char, $code,  1.0  ) );
end













rule "Init ScoreCard Params ScorecardCompoundPredicate"
 

  @Generated   
when
    ModelMarker( "ScorecardCompoundPredicate" ; enabled == true )
then
    
        insert( new BaselineScore( "ScorecardCompoundPredicate", 50.0, "ch1" ) );
        
            insert( new ScoreRow( "ScorecardCompoundPredicate",
                           20.0,
                           "ch1",
                           "reasonCh1",
                           "ch10" ) );
        
            insert( new ScoreRow( "ScorecardCompoundPredicate",
                           100.0,
                           "ch1",
                           "reasonCh1",
                           "ch11" ) );
        
            insert( new ScoreRow( "ScorecardCompoundPredicate",
                           200.0,
                           "ch1",
                           "reasonCh1",
                           "ch12" ) );
        
    
        insert( new BaselineScore( "ScorecardCompoundPredicate", 15.0, "ch2" ) );
        
            insert( new ScoreRow( "ScorecardCompoundPredicate",
                           10.0,
                           "ch2",
                           "reasonCh2",
                           "ch20" ) );
        
            insert( new ScoreRow( "ScorecardCompoundPredicate",
                           20.0,
                           "ch2",
                           "reasonCh2",
                           "ch21" ) );
        
    
end
```