private function compactValue($value, $definition, $activectx, $inversectx)
    {
        if ('@index' === $definition['@container']) {
            unset($value->{'@index'});
        }

        $numProperties = count(get_object_vars($value));

        // @id object
        if (property_exists($value, '@id')) {
            if (1 === $numProperties) {
                if ('@id' === $definition['@type']) {
                    return $this->compactIri($value->{'@id'}, $activectx, $inversectx);
                }

                if ('@vocab' === $definition['@type']) {
                    return $this->compactIri($value->{'@id'}, $activectx, $inversectx, null, true);
                }
            }

            return $value;
        }

        // @value object
        $criterion = (isset($value->{'@type'})) ? '@type' : null;
        $criterion = (isset($value->{'@language'})) ? '@language' : $criterion;

        if (null !== $criterion) {
            if ((2 === $numProperties) && ($value->{$criterion} === $definition[$criterion])) {
                return $value->{'@value'};
            }

            return $value;
        }

        // the object has neither a @type nor a @language property
        // check the active property's definition
        if (is_string($value->{'@value'}) && (null !== $definition['@language'])) {
            // if the property is language tagged or there's a default language,
            // we can't compact the value if it is a string
            return $value;
        }

        // we can compact the value
        return (1 === $numProperties) ? $value->{'@value'} : $value;
    }