Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ecdfff7
Generate powershell script for grpc models (I dont know if it works)
aerooneqq Jun 12, 2026
207531d
Fix models generation on windows, add windows script to solution folder
aerooneqq Jul 4, 2026
7bd0558
Try to promote rust version
aerooneqq Jul 4, 2026
aac06a6
Don't pass `pipeline_parts` everywhere
aerooneqq Jul 5, 2026
72b46f4
After-rebase fixes
aerooneqq Jul 5, 2026
00f57db
Remove explicit `Debug` impls
aerooneqq Jul 6, 2026
1d8b1c2
Remove explicit `Error` impls
aerooneqq Jul 6, 2026
56279d2
Remove unused imports
aerooneqq Jul 6, 2026
2643efa
Fix compilation
aerooneqq Jul 7, 2026
b75e1a6
Some cleanups
aerooneqq Jul 13, 2026
51e5a60
WIP on ECFG -> Petri Nets transformation
aerooneqq Aug 30, 2026
161f0f1
WIP on ECFG -> Petri Nets transformation
aerooneqq Aug 31, 2026
1240b33
Better silent transitions
aerooneqq Sep 1, 2026
9a23fec
Write silent transitions tags
aerooneqq Sep 1, 2026
589c8d8
WIP: add tests
aerooneqq Sep 3, 2026
a730c5b
Add backend ConvertEcfgToPetriNet pipeline part
aerooneqq Sep 4, 2026
8eed09e
cargo fmt
aerooneqq Sep 4, 2026
cf89438
Add frontend pipeline part
aerooneqq Sep 4, 2026
c736931
Serialize markings too
aerooneqq Sep 4, 2026
6f4093f
Make date optional for xes logs
aerooneqq Sep 5, 2026
0372073
Better perf during replay
aerooneqq Sep 5, 2026
27dc7f0
Use slices
aerooneqq Sep 5, 2026
2a3a6bb
Add bytes serialization to PNML
aerooneqq Sep 5, 2026
d8e2b89
Fixing some tests
aerooneqq Sep 5, 2026
6149538
Fixing petri nets serialization
aerooneqq Sep 6, 2026
9498c40
Fix places names in ECFG to Petri net conversion, update gold
aerooneqq Sep 6, 2026
93308ff
Check if there is last group
aerooneqq Sep 6, 2026
f2e08e2
Fix not sending context values for offline kafka pipelines
aerooneqq Sep 7, 2026
dc65d45
cargo fmt
aerooneqq Sep 7, 2026
a127d39
Fix execution results grouping
aerooneqq Sep 7, 2026
a4414da
Update CMAKE version to 4.2.0, update Visual Stusio generator to VS 1…
aerooneqq Sep 7, 2026
7cd8a40
Update Ficus integration tests gold
aerooneqq Sep 8, 2026
9f24598
Try to update to VS 2026 in CI
aerooneqq Sep 8, 2026
f38358a
Fix typo
aerooneqq Sep 8, 2026
0e7e113
Explicitly install cmake version
aerooneqq Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
dotnet-bxes-unit-tests:
runs-on: windows-2022
runs-on: windows-2025-vs2026

steps:
- uses: actions/checkout@v4
Expand All @@ -25,7 +25,7 @@ jobs:
run: dotnet test ./bxes/src/csharp/Bxes.Tests

rust-bxes-unit-tests:
runs-on: windows-2022
runs-on: windows-2025-vs2026

steps:
- uses: actions/checkout@v4
Expand All @@ -37,7 +37,7 @@ jobs:
RUSTFLAGS: ""

dotnet-procfiler-unit-tests:
runs-on: windows-2022
runs-on: windows-2025-vs2026

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -86,6 +86,11 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install CMake
uses: ssrobins/install-cmake@v1
with:
version: 4.2.0

- name: Setup docker
uses: docker/setup-qemu-action@v3

Expand Down
1 change: 1 addition & 0 deletions .run/windows/ProcfilerOnline.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set OnlineProcfilerSettings__KafkaSettings__TopicName=my-topic
set OnlineProcfilerSettings__KafkaSettings__BootstrapServers=localhost:9092

dotnet clean %PM_IDE_ROOT%/All.sln
dotnet build %PM_IDE_ROOT%/ProcfilerBuildTasks/ -c Release
dotnet build %PM_IDE_ROOT%/All.sln -c Release
dotnet build %PM_IDE_ROOT%/Procfiler/src/dotnet/ProcfilerLoggerProvider/ -c Release
dotnet build %PM_IDE_ROOT%/Procfiler/test_data/source/WFWebApp -c Release
Expand Down
1 change: 1 addition & 0 deletions All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{92C02EAF-93FB-4A2C-A235-8541D893163C}"
ProjectSection(SolutionItems) = preProject
scripts\macos\generate_grpc_models.sh = scripts\macos\generate_grpc_models.sh
scripts\windows\generate_grpc_models.ps1 = scripts\windows\generate_grpc_models.ps1
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "misc", "misc", "{2918C7E3-3FC8-48A5-ADDF-8358E888B40C}"
Expand Down
2 changes: 1 addition & 1 deletion Ficus/docker/run/Run.RustFicusBackend.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM rust:1.92.0 as build
FROM rust:1.93.0 as build

RUN apt update -y && apt upgrade -y
RUN apt-get update -y
Expand Down
2 changes: 1 addition & 1 deletion Ficus/docker/tests/Tests.Rust.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM rust:1.92.0 as build
FROM rust:1.93.0 as build

RUN apt update -y && apt upgrade -y
RUN apt-get update -y
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
@if (myIsLoading)
{
<div style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;">
<Loader />
<Loader/>
</div>

return;
Expand All @@ -48,7 +48,7 @@
</div>

<div class="pipeline-parts-context-values-outer-container">
@foreach (var (index, (_, results)) in myPipelinePartsExecutionResults.OrderBy(x => x.Value.Order).Index())
@foreach (var (index, results) in myPipelinePartsExecutionResults.OrderBy(x => x.Order).Index())
{
<PipelinePartResultsRenderer Results="results"
Lifetime="myCurrentLifetime"
Expand All @@ -60,11 +60,11 @@
@code
{
private readonly SequentialLifetimes myLifetimes = new(Lifetime.Eternal);
private IReadOnlyDictionary<Guid, PipelinePartExecutionResults> myPipelinePartsExecutionResults =
new Dictionary<Guid, PipelinePartExecutionResults>();

private IReadOnlyList<PipelinePartExecutionResults> myPipelinePartsExecutionResults = [];

private bool myIsLoading;

private Lifetime myCurrentLifetime;
private ProcessCaseData? myProcessCaseData;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface ISubscriptionsService
ISignal<Pipeline> AnyPipelineSubEntityUpdated { get; }

void StartUpdatesRequestingRoutine(CancellationToken token);
Task<IReadOnlyDictionary<Guid, PipelinePartExecutionResults>> GetCaseExecutionResult(ProcessCaseData data);
Task<IReadOnlyList<PipelinePartExecutionResults>> GetCaseExecutionResult(ProcessCaseData data);
}

public class SubscriptionsService(
Expand Down Expand Up @@ -54,7 +54,7 @@ public void StartUpdatesRequestingRoutine(CancellationToken token)
}, token);
}

public async Task<IReadOnlyDictionary<Guid, PipelinePartExecutionResults>> GetCaseExecutionResult(ProcessCaseData data)
public async Task<IReadOnlyList<PipelinePartExecutionResults>> GetCaseExecutionResult(ProcessCaseData data)
{
var result = await client.GetPipelineCaseContextValueAsync(new GrpcGetPipelineCaseContextValuesRequest
{
Expand All @@ -68,24 +68,29 @@ public async Task<IReadOnlyDictionary<Guid, PipelinePartExecutionResults>> GetCa
ProcessName = data.ProcessData.ProcessName
});

return result.ContextValues.Select((value, order) =>
{
var id = value.PipelinePartInfo.Id.ToGuid();

var results = value.ExecutionResults.Select(r => new PipelinePartExecutionResult
return result.ContextValues
.Select((x, order) => (Id: x.PipelinePartInfo.Id.ToGuid(), Order: order, Parts: x))
.GroupBy(x => x.Id)
.Select(group =>
{
ContextValues = r.ContextValues.Select(c => new ContextValueWrapper(c)).ToList()
}).ToList();
var results = group.SelectMany(x => x.Parts.ExecutionResults).Select(r => new PipelinePartExecutionResult
{
ContextValues = [.. r.ContextValues.Select(c => new ContextValueWrapper(c))]
}).ToList();

var partResults = new PipelinePartExecutionResults
{
PipelinePartName = value.PipelinePartInfo.Name,
Order = (uint)order,
Results = new ViewableList<PipelinePartExecutionResult>(results)
};
var (_, order, parts) = group.First();
var info = parts.PipelinePartInfo;

var partResults = new PipelinePartExecutionResults
{
PipelinePartName = info.Name,
Order = (uint)order,
Results = new ViewableList<PipelinePartExecutionResult>(results)
};

return (id, partResults);
}).ToDictionary();
return partResults;
})
.ToList();
}

private void ProcessState(GrpcSubscriptionAndPipelinesStateResponse reponse)
Expand Down
2 changes: 2 additions & 0 deletions Ficus/src/python/ficus/grpc_pipelines/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@
const_discover_ecfg = 'DiscoverECFG'
const_discover_loops_strict = 'DiscoverLoopsStrict'
const_discover_traces_timeline_diagram = 'DiscoverTracesTimelineDiagram'
const_convert_ecfg_to_petri_net = 'ConvertECFGToPetriNet'
const_serialize_petri_net_bytes = 'SerializePetriNetBytes'

const_prepare_software_log = 'PrepareSoftwareEventLog'
const_shorten_allocation_type = 'ShortenAllocationType'
Expand Down
26 changes: 26 additions & 0 deletions Ficus/src/python/ficus/grpc_pipelines/discovery_parts.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,29 @@ def to_grpc_part(self) -> GrpcPipelinePartBase:
append_bool_value(config, const_merge_sequences_of_events, self.merge_sequences_of_events)

return GrpcPipelinePartBase(defaultPart=create_default_pipeline_part(const_discover_ecfg, config))

class ConvertECFGToPetriNet(PipelinePart):
def to_grpc_part(self) -> GrpcPipelinePartBase:
return GrpcPipelinePartBase(defaultPart=create_default_pipeline_part(const_convert_ecfg_to_petri_net))

class SerializePetriNetPnmlBytes(PipelinePartWithCallback):
def __init__(self, save_path: str, use_names_as_ids:bool = False):
super().__init__()
self.save_path = save_path
self.use_names_as_ids = use_names_as_ids

def to_grpc_part(self) -> GrpcPipelinePartBase:
config = GrpcPipelinePartConfiguration()
append_bool_value(config, const_pnml_use_names_as_ids, self.use_names_as_ids)

part = create_complex_get_context_part(self.uuid,
self.__class__.__name__,
[const_bytes],
const_serialize_petri_net_bytes,
config)

return GrpcPipelinePartBase(complexContextRequestPart=part)

def execute_callback(self, values: dict[str, GrpcContextValue]):
file_bytes = from_grpc_bytes(values[const_bytes].bytes)
write_file_bytes(self.save_path, file_bytes.bytes)
6 changes: 5 additions & 1 deletion Ficus/src/python/infra/generate_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ def generate_models():

os.mkdir(models_dir)

python = '/usr/local/bin/python3'
if os.name == 'nt':
python = 'python'
else:
python = '/usr/local/bin/python3'

os.popen(f'{python} -m pip install grpcio-tools').read()
packages = []

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ impl<'a> TraceXesEventLogIterator<'a> {
match self.reader.borrow_mut().read_event_into(&mut self.buffer) {
Ok(quick_xml::events::Event::End(end)) => match end.name().0 {
EVENT_TAG_NAME => {
name.as_ref()?;
date?;
let name = name?;
let date = date.unwrap_or(DateTime::<Utc>::MIN_UTC);

let event = XesEventImpl::new_all_fields(name.unwrap(), date.unwrap(), Some(payload));
let event = XesEventImpl::new_all_fields(name, date, Some(payload));
return Some(event);
}
_ => continue,
Expand Down
13 changes: 2 additions & 11 deletions Ficus/src/rust/ficus/src/event_log/xes/xes_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,14 @@ use crate::{
},
};
use chrono::{DateTime, Utc};
use std::{
collections::HashMap,
fmt::{Debug, Formatter},
sync::Arc,
};
use std::{collections::HashMap, fmt::Debug, sync::Arc};

#[derive(Debug)]
pub struct XesEventImpl {
event_base: EventBase,
payload: Option<HashMap<Arc<str>, EventPayloadValue>>,
}

impl Debug for XesEventImpl {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name_pointer())
}
}

impl XesEventImpl {
pub fn new_all_fields(name: Arc<str>, timestamp: DateTime<Utc>, payload: Option<HashMap<Arc<str>, EventPayloadValue>>) -> Self {
Self {
Expand Down
20 changes: 3 additions & 17 deletions Ficus/src/rust/ficus/src/features/clustering/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use crate::{
pipelines::errors::pipeline_errors::{PipelinePartExecutionError, RawPartExecutionError},
utils::dataset::dataset::LabeledDataset,
};
use std::fmt::Display;

pub type ClusteringResult = Result<LabeledDataset, ClusteringError>;

#[derive(Debug)]
pub enum ClusteringError {
NoRepeatSet,
FailedToCreateNdArray,
Expand All @@ -14,21 +14,7 @@ pub enum ClusteringError {
}

impl From<ClusteringError> for PipelinePartExecutionError {
fn from(val: ClusteringError) -> Self {
PipelinePartExecutionError::Raw(RawPartExecutionError::new(val.to_string()))
}
}

impl Display for ClusteringError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(
match self {
Self::NoRepeatSet => "NoRepeatSet".to_owned(),
Self::FailedToCreateNdArray => "FailedToCreateNdArray".to_owned(),
Self::FailedToCalculateSilhouetteScore => "FailedToCalculateSilhouetteScore".to_owned(),
Self::RawError(message) => message.clone(),
}
.as_str(),
)
fn from(err: ClusteringError) -> Self {
PipelinePartExecutionError::Raw(RawPartExecutionError::new(format!("{err:?}")))
}
}
8 changes: 2 additions & 6 deletions Ficus/src/rust/ficus/src/features/discovery/alpha/alpha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,7 @@ fn add_one_length_loops(provider: &impl AlphaPlusRelationsProvider, original_log
}
}

let id = petri_net.add_transition(Transition::empty(
transition_name.to_owned(),
false,
Some(transition_name.to_owned()),
));
let id = petri_net.add_transition(Transition::empty(transition_name.to_owned(), Some(transition_name.to_owned())));

let place_id = match petri_net.find_place_id_by_name(alpha_set.to_string().as_str()) {
Some(found_place_id) => found_place_id,
Expand Down Expand Up @@ -196,7 +192,7 @@ fn create_petri_net(info: &dyn EventLogInfo, alpha_sets: Vec<&AlphaSet>) -> Defa
let mut petri_net = PetriNet::default();
let mut event_classes_to_transition_ids = HashMap::new();
for class in info.all_event_classes() {
let id = petri_net.add_transition(Transition::empty(class.to_owned(), false, Some(class.to_owned())));
let id = petri_net.add_transition(Transition::empty(class.to_owned(), Some(class.to_owned())));
event_classes_to_transition_ids.insert(class.as_ref(), id);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ pub fn discover_petri_net_alpha_plus_plus_nfc<TLog: EventLog>(log: &TLog) -> Def
let mut resulting_net = DefaultPetriNet::default();
let mut transitions_to_ids = HashMap::new();
for transition in info.all_event_classes().iter().copied().chain(one_length_loop_transitions.iter()) {
let id = resulting_net.add_transition(Transition::empty((*transition).to_owned(), false, Some((*transition).to_owned())));
let id = resulting_net.add_transition(Transition::empty((*transition).to_owned(), Some((*transition).to_owned())));
transitions_to_ids.insert(transition, id);
}

Expand Down
Loading
Loading